diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index 9e8d20c6..c5dd2620 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -6,11 +6,11 @@ on: permissions: {} env: - NODE_VERSION: 18.17.1 + NODE_VERSION: 22.17.0 TEST_RESULTS_DIRECTORY: . # Force a path with spaces and unicode chars to test extension works in these scenarios - special-working-directory: './🐍 🐛' - special-working-directory-relative: '🐍 🐛' + special-working-directory: './testDir' + special-working-directory-relative: 'testDir' jobs: build-vsix: diff --git a/.github/workflows/push-check.yml b/.github/workflows/push-check.yml index 722446af..c8e956a9 100644 --- a/.github/workflows/push-check.yml +++ b/.github/workflows/push-check.yml @@ -11,11 +11,11 @@ on: permissions: {} env: - NODE_VERSION: 18.17.1 + NODE_VERSION: 22.17.0 TEST_RESULTS_DIRECTORY: . # Force a path with spaces and unicode chars to test extension works in these scenarios - special-working-directory: './🐍 🐛' - special-working-directory-relative: '🐍 🐛' + special-working-directory: './testDir' + special-working-directory-relative: 'testDir' jobs: build-vsix: diff --git a/.gitignore b/.gitignore index ffe0c9cb..d35af712 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,9 @@ node_modules bundled/libs/ **/__pycache__ **/.pytest_cache -**/.vs \ No newline at end of file +**/.vs + +# Generated files (sources live in pre-built/) +l10n/bundle.l10n.*.json +package.nls.*.json +telemetry.json \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..6d6c8844 --- /dev/null +++ b/.npmrc @@ -0,0 +1,4 @@ +# Force public npm registry to avoid CI auth (E401) when no token is provided +registry=https://registry.npmjs.org/ +# Do not require auth for public installs +always-auth=false diff --git a/.vscode/launch.json b/.vscode/launch.json index 08fec254..0b406f92 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -24,12 +24,12 @@ "request": "launch", "runtimeExecutable": "${execPath}", "args": [ - "./out/test/**/*.unit.test.js", "--extensionDevelopmentPath=${workspaceFolder}", - "--extensionTestsPath=${workspaceFolder}/out/test/unittest/index", - //"--grep", "", - "--timeout=300000" + "--extensionTestsPath=${workspaceFolder}/out/test/unittest/index" ], + // "env": { + // "TEST_GREP": "Python API Tests" + // }, "outFiles": ["${workspaceFolder}/out/**/*.js"], "preLaunchTask": "tasks: watch-tests" } diff --git a/.vscodeignore b/.vscodeignore index cb1e5cf4..39c0e6bf 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -4,6 +4,7 @@ build/** out/** node_modules/** src/** +pre-built/** .gitignore .yarnrc webpack.config.js diff --git a/README.md b/README.md index 59bc8a3b..051cbe01 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,4 @@ You can reference the table below to find the most recent Python Debugger extens ## Data and telemetry -The Debugpy Extension for Visual Studio Code collects usage data and sends it to Microsoft to help improve our products and services. Read our [privacy statement](https://privacy.microsoft.com/privacystatement) to learn more. This extension respects the `telemetry.enableTelemetry` setting which you can learn more about at https://code.visualstudio.com/docs/supporting/faq#_how-to-disable-telemetry-reporting. +The Debugpy Extension for Visual Studio Code collects usage data and sends it to Microsoft to help improve our products and services. Read our [privacy statement](https://privacy.microsoft.com/privacystatement) to learn more. This extension respects the `telemetry.telemetryLevel` setting which you can learn more about at https://code.visualstudio.com/docs/supporting/faq#_how-to-disable-telemetry-reporting. diff --git a/build/NuGet.config b/build/NuGet.config new file mode 100644 index 00000000..a3a2e4f4 --- /dev/null +++ b/build/NuGet.config @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/build/azure-devdiv-pipeline.pre-release.yml b/build/azure-devdiv-pipeline.pre-release.yml new file mode 100644 index 00000000..3ac8ddf4 --- /dev/null +++ b/build/azure-devdiv-pipeline.pre-release.yml @@ -0,0 +1,124 @@ +# Run on a schedule +trigger: none +pr: none + +schedules: + - cron: '0 10 * * 1-5' # 10AM UTC (2AM PDT) MON-FRI (VS Code Pre-release builds at 9PM PDT) + displayName: Nightly Pre-Release Schedule + always: false # only run if there are source code changes + branches: + include: + - main + +resources: + repositories: + - repository: MicroBuildTemplate + type: git + name: 1ESPipelineTemplates/MicroBuildTemplate + ref: refs/tags/release +variables: + - name: TeamName + value: VSCode-python-debugger + - name: VsixName + value: python-debugger.vsix + - name: AZURE_ARTIFACTS_FEED + value: 'https://devdiv.pkgs.visualstudio.com/DevDiv/_packaging/Pylance_PublicPackages/npm/registry/' +parameters: + - name: publishExtension + displayName: 🚀 Publish Extension + type: boolean + default: false + + - name: buildPlatforms + type: object + default: + - name: Linux + vsceTarget: '' + - name: Linux + packageArch: arm64 + vsceTarget: linux-arm64 + - name: Linux + packageArch: arm + vsceTarget: linux-armhf + - name: Linux + packageArch: x64 + vsceTarget: linux-x64 + - name: MacOS + packageArch: arm64 + vsceTarget: darwin-arm64 + - name: MacOS + packageArch: x64 + vsceTarget: darwin-x64 + - name: Windows + packageArch: arm + vsceTarget: win32-arm64 + - name: Windows + packageArch: x64 + vsceTarget: win32-x64 + + - name: buildSteps + type: stepList + default: + - script: npm ci + displayName: Install NPM dependencies + + - script: python -m pip install -U pip + displayName: Upgrade pip + + - script: python -m pip install wheel + displayName: Install wheel + + - script: python -m pip install nox + displayName: Install nox + + - script: python -m nox --session install_bundled_libs + displayName: Install Python dependencies + + - script: python ./build/update_ext_version.py --for-publishing + displayName: Update build number + + - pwsh: Copy-Item -Path "pre-built/*" -Destination "." -Recurse -Force + displayName: Copy pre-built files + + - script: npm run package + displayName: Build extension + +extends: + template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate + parameters: + sdl: + sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES + codeSignValidation: + enabled: true + sbom: + enabled: false # Disable global SBOM generation; we'll enable selectively per artifact output + pool: + name: AzurePipelines-EO + os: windows + + customBuildTags: + - ES365AIMigrationTooling + stages: + - stage: Build + displayName: Build & Package Extension + jobs: + - template: build/templates/package.yml@self + parameters: + buildPlatforms: ${{ parameters.buildPlatforms }} + buildSteps: ${{ parameters.buildSteps }} + isPreRelease: true + standardizedVersioning: true + + - stage: Publish + displayName: Publish Extension + dependsOn: Build + jobs: + - template: build/templates/publish-extension.yml@self + parameters: + buildPlatforms: ${{ parameters.buildPlatforms }} + publishExtension: ${{ parameters.publishExtension }} + preRelease: true + teamName: $(TeamName) + ghCreateTag: true + ghCreateRelease: true + ghReleaseAddChangeLog: true diff --git a/build/azure-devdiv-pipeline.stable.yml b/build/azure-devdiv-pipeline.stable.yml new file mode 100644 index 00000000..d8219b3e --- /dev/null +++ b/build/azure-devdiv-pipeline.stable.yml @@ -0,0 +1,118 @@ +name: Publish Release +trigger: none +# branches: +# include: +# - release* +# tags: +# include: ['*'] +pr: none + +resources: + repositories: + - repository: MicroBuildTemplate + type: git + name: 1ESPipelineTemplates/MicroBuildTemplate + ref: refs/tags/release +variables: + - name: TeamName + value: VSCode-python-debugger + - name: VsixName + value: python-debugger.vsix + - name: AZURE_ARTIFACTS_FEED + value: 'https://devdiv.pkgs.visualstudio.com/DevDiv/_packaging/Pylance_PublicPackages/npm/registry/' + +parameters: + - name: publishExtension + displayName: 🚀 Publish Extension + type: boolean + default: false + + - name: buildPlatforms + type: object + default: + - name: Linux + vsceTarget: '' + - name: Linux + packageArch: arm64 + vsceTarget: linux-arm64 + - name: Linux + packageArch: arm + vsceTarget: linux-armhf + - name: Linux + packageArch: x64 + vsceTarget: linux-x64 + - name: MacOS + packageArch: arm64 + vsceTarget: darwin-arm64 + - name: MacOS + packageArch: x64 + vsceTarget: darwin-x64 + - name: Windows + packageArch: arm + vsceTarget: win32-arm64 + - name: Windows + packageArch: x64 + vsceTarget: win32-x64 + + - name: buildSteps + type: stepList + default: + - script: npm ci + displayName: Install NPM dependencies + + - script: python -m pip install -U pip + displayName: Upgrade pip + + - script: python -m pip install wheel + displayName: Install wheel + + - script: python -m pip install nox + displayName: Install nox + + - script: python -m nox --session install_bundled_libs + displayName: Install Python dependencies + + - script: python ./build/update_ext_version.py --release --for-publishing + displayName: Update build number + + - pwsh: Copy-Item -Path "pre-built/*" -Destination "." -Recurse -Force + displayName: Copy pre-built files + + - script: npm run package + displayName: Build extension + +extends: + template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate + parameters: + sdl: + sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES + codeSignValidation: + enabled: true + sbom: + enabled: false # Disable global SBOM generation; we'll enable selectively per artifact output + pool: + name: AzurePipelines-EO + os: windows + + customBuildTags: + - ES365AIMigrationTooling + stages: + - stage: Build + displayName: Build & Package Extension + jobs: + - template: build/templates/package.yml@self + parameters: + buildPlatforms: ${{ parameters.buildPlatforms }} + buildSteps: ${{ parameters.buildSteps }} + isPreRelease: false + + - stage: Publish + displayName: Publish Extension + dependsOn: Build + jobs: + - template: build/templates/publish-extension.yml@self + parameters: + buildPlatforms: ${{ parameters.buildPlatforms }} + publishExtension: ${{ parameters.publishExtension }} + preRelease: false + teamName: $(TeamName) diff --git a/build/azure-pipeline.pre-release.yml b/build/azure-pipeline.pre-release.yml index c97169d0..2db74326 100644 --- a/build/azure-pipeline.pre-release.yml +++ b/build/azure-pipeline.pre-release.yml @@ -58,7 +58,7 @@ extends: buildSteps: - task: NodeTool@0 inputs: - versionSpec: '18.17.1' + versionSpec: '22.17.0' displayName: Select Node version - task: UsePythonVersion@0 diff --git a/build/azure-pipeline.stable.yml b/build/azure-pipeline.stable.yml index 5a743734..452ab5e9 100644 --- a/build/azure-pipeline.stable.yml +++ b/build/azure-pipeline.stable.yml @@ -53,7 +53,7 @@ extends: buildSteps: - task: NodeTool@0 inputs: - versionSpec: '18.17.1' + versionSpec: '22.17.0' displayName: Select Node version - task: UsePythonVersion@0 diff --git a/build/sign.proj b/build/sign.proj new file mode 100644 index 00000000..95ccd155 --- /dev/null +++ b/build/sign.proj @@ -0,0 +1,59 @@ + + + + + + + + + Debug + + .\ + + $(BaseOutputDirectory)/intermediate + $(BaseOutputDirectory) + + + + + + + + + + + + + + + + + + + + + + + + + + + VSCodePublisher + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + diff --git a/build/templates/createGitHubRelease.yml b/build/templates/createGitHubRelease.yml new file mode 100644 index 00000000..7c136696 --- /dev/null +++ b/build/templates/createGitHubRelease.yml @@ -0,0 +1,27 @@ +parameters: + - name: isPreRelease + type: boolean + - name: ghReleaseAddChangeLog + type: boolean + - name: tagName + type: string + +steps: + - task: GitHubRelease@1 + inputs: + gitHubConnection: 'Github-Pylance' # The name of the GitHub service connection + repositoryName: $(Build.Repository.Name) + action: edit # Creates a new release if one does not exist (https://github.com/microsoft/azure-pipelines-tasks/blob/master/Tasks/GitHubReleaseV1/main.ts#85) + addChangelog: ${{ parameters.ghReleaseAddChangeLog }} + changeLogType: issueBased + changeLogLabels: '[{ "label" : "feature-request", "displayName" : "Feature Requests", "state" : "closed" }, { "label" : "bug", "displayName" : "Bugs", "state" : "closed" }]' + tagSource: userSpecifiedTag + tag: ${{ parameters.tagName }} + title: ${{ parameters.tagName }} + isPreRelease: ${{ parameters.isPreRelease }} + ${{ if eq(parameters.isPreRelease, true) }}: + changeLogCompareToRelease: lastNonDraftRelease + ${{ else }}: + changeLogCompareToRelease: lastFullRelease + displayName: 🐙 Github release + continueOnError: true diff --git a/build/templates/modify-extension-version.yml b/build/templates/modify-extension-version.yml new file mode 100644 index 00000000..810049d7 --- /dev/null +++ b/build/templates/modify-extension-version.yml @@ -0,0 +1,42 @@ +parameters: + - name: workingDirectory + type: string + +steps: + # Updates extension version in package.json using the Azure DevOps build number. + # + # Build number format: YYYYMMDD.R (e.g., 20260112.3) + # - YYYYMMDD: date segment + # - R: revision number (1, 2, 3... for builds on the same day) + # + # Resulting version: {major}.{minor}.{YYYYMMDDRR} + # - The revision is zero-padded to 2 digits (e.g., 03) + # - Example: 2025.19.2026011203 + # + # This keeps versions unique and monotonically increasing across builds. + - pwsh: | + $packagejsonPath = './package.json' + + $json = Get-Content $packagejsonPath | ConvertFrom-Json -Depth 100 + + $newProps = @{ } + + $stableVersion = $json.version -split '\.' + $major = $stableVersion[0] + $minor = $stableVersion[1] + + # Build number format: YYYYMMDD.R (e.g., 20260112.3) + $buildNumber = '$(Build.BuildNumber)' + $dateSegment, $revisionSegment = $buildNumber -split '\.' + + # Combine date + zero-padded revision to form the patch version + # e.g., 20260112 + 03 = 2026011203 + $patch = $dateSegment + ($revisionSegment.PadLeft(2, '0')) + $newProps.version = "$major.$minor.$patch" + + Write-Host "Updating version FROM: $($json.version) TO: $($newProps.version)" + + $prereleasePackageJson = $json | Add-Member -NotePropertyMembers $newProps -PassThru -Force + $prereleasePackageJson | ConvertTo-Json -Depth 100 | Set-Content $packagejsonPath + displayName: Update the extension version in package.json + workingDirectory: ${{ parameters.workingDirectory }} diff --git a/build/templates/package.yml b/build/templates/package.yml new file mode 100644 index 00000000..1ed988eb --- /dev/null +++ b/build/templates/package.yml @@ -0,0 +1,133 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +# Template for building platform-specific VSIX packages +# Sets VSCETARGET environment variable for noxfile.py to select correct debugpy wheels +# Iterates over buildPlatforms to create a job per platform + +parameters: + - name: buildPlatforms + type: object + displayName: 'List of platforms to build' + + - name: buildSteps + type: stepList + default: [] + displayName: 'Build steps to execute' + + - name: isPreRelease + type: boolean + default: false + displayName: 'Is this a pre-release build' + + - name: standardizedVersioning + type: boolean + default: false + displayName: 'Use standardized versioning (YYYYMMDDRR format)' + + - name: vscePackageArgs + type: string + default: '' + displayName: 'Additional vsce package arguments' + + - name: workingDirectory + type: string + default: '$(Build.SourcesDirectory)' + displayName: 'Working directory for packaging' + +jobs: + - ${{ each platform in parameters.buildPlatforms }}: + - job: Build_${{ replace(coalesce(platform.vsceTarget, 'universal'), '-', '_') }} + displayName: "Build ${{ coalesce(platform.vsceTarget, 'universal') }}" + + ${{ if eq(platform.name, 'Linux') }}: + pool: + name: AzurePipelines-EO + image: 1ESPT-Ubuntu22.04 + os: linux + + ${{ if eq(platform.name, 'MacOS') }}: + pool: + name: Azure Pipelines + image: macos-latest + os: macOS + + ${{ if eq(platform.name, 'Windows') }}: + pool: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + os: windows + + variables: + packageArch: ${{ coalesce(platform.packageArch, '') }} + vsceTarget: ${{ platform.vsceTarget }} + ${{ if eq(platform.name, 'MacOS') }}: + BUILDSECMON_OPT_IN: false + + templateContext: + outputs: + - output: pipelineArtifact + displayName: "Publish VSIX for ${{ coalesce(platform.vsceTarget, 'universal') }}" + targetPath: '$(Build.ArtifactStagingDirectory)/drop' + artifactName: vsix-${{ coalesce(platform.vsceTarget, 'universal') }} + + steps: + - template: setup.yml@self + + - ${{ if and(eq(parameters.isPreRelease, true), eq(parameters.standardizedVersioning, true)) }}: + - template: modify-extension-version.yml@self + parameters: + workingDirectory: ${{ parameters.workingDirectory }} + + - bash: | + echo "##vso[task.setvariable variable=VSCETARGET]${{ platform.vsceTarget }}" + echo "Building for target: ${{ platform.vsceTarget }}" + displayName: 'Set VSCETARGET variable' + + - ${{ each buildStep in parameters.buildSteps }}: + - ${{ buildStep }} + + - ${{ if eq(platform.vsceTarget, '') }}: + - bash: | + VSIX=$(node -p "require(\"./package.json\").publisher + \".\" + require(\"./package.json\").name + \".\" + require(\"./package.json\").version + \".universal.vsix\"") + echo "##vso[task.setvariable variable=VSIX;isOutput=true]$VSIX" + name: SetExtensionName + displayName: 🗄 Set VSIX file name + workingDirectory: ${{ parameters.workingDirectory }} + + - ${{ if ne(platform.vsceTarget, '') }}: + - bash: | + VSIX=$(node -p "require(\"./package.json\").publisher + \".\" + require(\"./package.json\").name + \".\" + require(\"./package.json\").version + \".\" + \"${{ platform.vsceTarget }}\" + \".vsix\"") + echo "##vso[task.setvariable variable=VSIX;isOutput=true]$VSIX" + name: SetExtensionName + displayName: 🗄 Set VSIX file name + workingDirectory: ${{ parameters.workingDirectory }} + + - ${{ if eq(parameters.isPreRelease, false) }}: + - ${{ if eq(platform.vsceTarget, '') }}: + - script: npx @vscode/vsce@latest package -o $(Build.BinariesDirectory)/$(SetExtensionName.VSIX) ${{ parameters.vscePackageArgs }} + displayName: 💾 Package extension + workingDirectory: ${{ parameters.workingDirectory }} + + - ${{ if ne(platform.vsceTarget, '') }}: + - script: npx @vscode/vsce@latest package -o $(Build.BinariesDirectory)/$(SetExtensionName.VSIX) --target ${{ platform.vsceTarget }} ${{ parameters.vscePackageArgs }} + displayName: 💾 Package extension + workingDirectory: ${{ parameters.workingDirectory }} + + - ${{ if eq(parameters.isPreRelease, true) }}: + - ${{ if eq(platform.vsceTarget, '') }}: + - script: npx @vscode/vsce@latest package -o $(Build.BinariesDirectory)/$(SetExtensionName.VSIX) --pre-release ${{ parameters.vscePackageArgs }} + displayName: 💾 Package pre-release extension + workingDirectory: ${{ parameters.workingDirectory }} + + - ${{ if ne(platform.vsceTarget, '') }}: + - script: npx @vscode/vsce@latest package -o $(Build.BinariesDirectory)/$(SetExtensionName.VSIX) --target ${{ platform.vsceTarget }} --pre-release ${{ parameters.vscePackageArgs }} + displayName: 💾 Package pre-release extension + workingDirectory: ${{ parameters.workingDirectory }} + + - task: CopyFiles@2 + inputs: + sourceFolder: $(Build.BinariesDirectory) + contents: '*.vsix' + targetFolder: $(Build.ArtifactStagingDirectory)/drop + displayName: 📦 Copy VSIX to staging diff --git a/build/templates/publish-extension.yml b/build/templates/publish-extension.yml new file mode 100644 index 00000000..163cb04d --- /dev/null +++ b/build/templates/publish-extension.yml @@ -0,0 +1,223 @@ +# Template (jobs): Sign and Publish Extension +# Encapsulates Sign, optional manual validation, and Publish jobs with MicroBuild signing. +# This template defines multiple jobs with templateContext for MicroBuild signing. +# +# Usage (example inside a stage): +# jobs: +# - template: build/templates/publish-extension.yml@self +# parameters: +# buildPlatforms: ${{ parameters.buildPlatforms }} +# publishExtension: ${{ parameters.publishExtension }} +# preRelease: false +# teamName: $(TeamName) +# ghCreateRelease: true +# ghCreateTag: true +# waitForValidation: true +# +# Notes: +# - Requires MicroBuild pool (VSEngSS-MicroBuild2022-1ES) for signing. +# - Downloads platform-specific artifacts from previous stage. +# - Publishes signed artifacts as 'extension' pipeline artifact with SBOM. +# - Optionally creates a GitHub release and waits for manual validation before marketplace publishing. + +parameters: + # Build platforms + - name: buildPlatforms + type: object + displayName: 'List of platforms to sign and publish' + + # Signing parameters + - name: signType + type: string + default: real + displayName: 'MicroBuild sign type (real or test)' + - name: verifySignature + type: boolean + default: true + displayName: 'Verify signature after signing' + - name: teamName + type: string + default: VSCode-python-debugger + displayName: 'Team name for signing' + + # Publishing parameters + - name: publishExtension + type: boolean + default: false + displayName: 'Publish extension to marketplace' + - name: preRelease + type: boolean + default: false + displayName: 'Publish as pre-release' + - name: azureSubscription + type: string + default: PylancePublishPipelineSecureConnectionWithManagedIdentity + displayName: 'Azure subscription for marketplace auth' + + # GitHub Release parameters + - name: ghCreateTag + type: boolean + default: false + displayName: 'Create GitHub tag' + - name: ghCreateRelease + type: boolean + default: false + displayName: 'Create GitHub release' + - name: ghReleaseAddChangeLog + type: boolean + default: true + displayName: 'Add changelog to GitHub release' + - name: ghTagPrefix + type: string + default: 'v' + displayName: 'Prefix for GitHub tag (e.g., v for v2025.1.0)' + + # Manual validation parameters + - name: waitForValidation + type: boolean + default: true + displayName: 'Wait for manual validation before publishing' + - name: validationNotifyUsers + type: string + default: '' + displayName: 'Users to notify for manual validation (comma-separated emails)' + - name: validationInstructions + type: string + default: 'Please test the latest draft release then approve to publish to marketplace.' + displayName: 'Instructions for manual validation' + - name: validationTimeoutInMinutes + type: number + default: 1440 + displayName: 'Timeout for manual validation in minutes (default: 1 day)' + + # Paths + - name: workingDirectory + type: string + default: '$(Build.StagingDirectory)\extension' + displayName: 'Working directory for signing artifacts' + - name: publishFolder + type: string + default: extension + displayName: 'Folder containing signed artifacts for publishing' + - name: manifestName + type: string + default: extension.manifest + displayName: 'Manifest filename' + - name: signatureName + type: string + default: extension.signature.p7s + displayName: 'Signature filename' + +jobs: + # Job 1: Sign extension and create GitHub release + - job: Sign + displayName: Sign Extension + pool: + name: VSEngSS-MicroBuild2022-1ES + os: windows + templateContext: + mb: + signing: + enabled: true + signType: ${{ parameters.signType }} + signWithProd: true + outputs: + - output: pipelineArtifact + displayName: 'Publish Extension Artifact' + targetPath: '${{ parameters.workingDirectory }}' + artifactName: extension + sbomEnabled: true + steps: + # Download platform-specific artifacts to Build.BinariesDirectory + - ${{ each platform in parameters.buildPlatforms }}: + - ${{ if eq(platform.vsceTarget, '') }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: vsix-universal + targetPath: $(Build.BinariesDirectory)/vsix-universal + displayName: 🚛 Download extension (universal) + + - ${{ if ne(platform.vsceTarget, '') }}: + - task: DownloadPipelineArtifact@2 + inputs: + artifactName: vsix-${{ platform.vsceTarget }} + targetPath: $(Build.BinariesDirectory)/vsix-${{ platform.vsceTarget }} + displayName: 🚛 Download extension (${{ platform.vsceTarget }}) + + - template: sign.yml + parameters: + buildPlatforms: ${{ parameters.buildPlatforms }} + workingDirectory: ${{ parameters.workingDirectory }} + signType: ${{ parameters.signType }} + verifySignature: ${{ parameters.verifySignature }} + teamName: ${{ parameters.teamName }} + + # Job 2: Publish to marketplace + - ${{ if eq(parameters.publishExtension, true) }}: + - job: Publish + displayName: Publish to Marketplace and GitHub + dependsOn: Sign + pool: + name: AzurePipelines-EO + image: 1ESPT-Windows2022 + os: windows + templateContext: + type: releaseJob # This makes a job a release job + isProduction: true # Indicates a production release + steps: + - template: setup.yml + parameters: + installNode: true + installPython: false + + - task: 1ES.DownloadPipelineArtifact@1 + inputs: + artifactName: extension + targetPath: $(Build.ArtifactStagingDirectory)/${{ parameters.publishFolder }} + displayName: 🚛 Download signed extension + + # Extract VSIX to read publisher/version for GitHub release tagging. + # Use Agent.TempDirectory to avoid reusing Build.ArtifactStagingDirectory which + # is reserved for final artifact staging. + - task: ExtractFiles@1 + inputs: + archiveFilePatterns: $(Build.ArtifactStagingDirectory)/${{ parameters.publishFolder }}/**/*.vsix + destinationFolder: $(Agent.TempDirectory)/vsix-extracted + cleanDestinationFolder: true + overwriteExistingFiles: true + displayName: 📦 Extract VSIX package + + - pwsh: | + $extensionDir = Get-ChildItem -Path . -Directory -Filter 'extension*' | Select-Object -First 1 + if (-not $extensionDir) { + throw "Could not find extracted extension folder under: $PWD" + } + + $packageJsonPath = Join-Path $extensionDir.FullName 'package.json' + if (-not (Test-Path $packageJsonPath)) { + throw "Could not find package.json at: $packageJsonPath" + } + + $package = Get-Content $packageJsonPath -Raw | ConvertFrom-Json + Write-Host "##vso[task.setvariable variable=publisher;isOutput=true]$($package.publisher)" + Write-Host "##vso[task.setvariable variable=version;isOutput=true]$($package.version)" + name: SetPublisherAndVersion + displayName: 📋 Get Publisher & Version + workingDirectory: $(Agent.TempDirectory)/vsix-extracted + + # Get version from package.json for GitHub release tagging + - ${{ if and(eq(parameters.ghCreateTag, true), eq(parameters.ghCreateRelease, true)) }}: + - template: createGitHubRelease.yml + parameters: + isPreRelease: ${{ parameters.preRelease }} + ghReleaseAddChangeLog: ${{ parameters.ghReleaseAddChangeLog }} + tagName: ${{ parameters.ghTagPrefix }}$(SetPublisherAndVersion.version) + + - template: publish.yml + parameters: + azureSubscription: ${{ parameters.azureSubscription }} + buildPlatforms: ${{ parameters.buildPlatforms }} + manifestName: ${{ parameters.manifestName }} + signatureName: ${{ parameters.signatureName }} + publishFolder: ${{ parameters.publishFolder }} + preRelease: ${{ parameters.preRelease }} diff --git a/build/templates/publish.yml b/build/templates/publish.yml new file mode 100644 index 00000000..66ac7f9f --- /dev/null +++ b/build/templates/publish.yml @@ -0,0 +1,131 @@ +# Template (steps): PublishMarketplace for VS Code extension +# Publishes platform-specific VSIX packages to the VS Code Marketplace. +# Iterates over buildPlatforms to publish each platform's signed artifacts. +# +# Usage (example inside a stage job): +# steps: +# - template: build/templates/publish.yml@self +# parameters: +# azureSubscription: PublishServiceConnectionWithManagedIdentity +# buildPlatforms: +# - name: Linux +# vsceTarget: '' +# - name: Linux +# vsceTarget: linux-arm64 +# manifestName: extension.manifest +# signatureName: extension.signature.p7s +# publishFolder: extension +# preRelease: true +# +# Notes: +# - Azure DevOps Marketplace resource GUID (499b84ac-1321-427f-aa17-267ca6975798) is hardcoded in publish script. +# - This uses Managed Identity via AzureCLI@2 to acquire an AAD token and passes it as a PAT. +# - Requires extension artifacts already signed (signature file present). +# - Node & vsce expected to be prepared by parent pipeline; omit local installation here. +# - Artifacts are expected at: $(Build.ArtifactStagingDirectory)/publishFolder/{platform}/ + +parameters: + - name: azureSubscription + type: string + - name: buildPlatforms + type: object + displayName: 'List of platforms to publish' + - name: manifestName + type: string + default: extension.manifest + - name: signatureName + type: string + default: extension.signature.p7s + - name: publishFolder + type: string + default: extension + - name: preRelease + type: boolean + default: false + +steps: + # Node & vsce expected to be prepared by parent pipeline; omit local installation. + + # Assumes files already present at $(Build.ArtifactStagingDirectory)/publishFolder/{platform}/ + + # Step 1: Acquire token only (store secret variable MarketplaceAADToken) + - task: AzureCLI@2 + displayName: Acquire Marketplace AAD token + inputs: + azureSubscription: ${{ parameters.azureSubscription }} + scriptType: pscore + scriptLocation: inlineScript + inlineScript: | + $resource = "499b84ac-1321-427f-aa17-267ca6975798" + Write-Host "Acquiring AAD token for resource: $resource" + az rest -u https://app.vssps.visualstudio.com/_apis/profile/profiles/me --resource $resource | Out-Null + $aadToken = az account get-access-token --query accessToken --resource $resource -o tsv + if (-not $aadToken) { Write-Error 'Failed to acquire AAD token.'; exit 1 } + Write-Host "##vso[task.setvariable variable=MarketplaceAADToken;isSecret=true]$aadToken" + Write-Host "Token stored in secret variable MarketplaceAADToken" + + # Step 2: Publish each platform + - ${{ each platform in parameters.buildPlatforms }}: + - task: PowerShell@2 + displayName: "Publish extension (${{ coalesce(platform.vsceTarget, 'universal') }})" + inputs: + targetType: inline + script: | + $aadToken = "$(MarketplaceAADToken)" + if (-not $aadToken) { Write-Error 'MarketplaceAADToken is empty (token acquisition failed).'; exit 1 } + + $platformFolder = "${{ coalesce(platform.vsceTarget, 'universal') }}" + $root = "$(Build.ArtifactStagingDirectory)/${{ parameters.publishFolder }}/$platformFolder" + + Write-Host "Publishing platform: $platformFolder" + Write-Host "Artifact folder: $root" + + if (-not (Test-Path $root)) { Write-Error "Platform folder not found: $root"; exit 1 } + + # Find VSIX file dynamically + $vsixFile = Get-ChildItem -Path $root -Filter "*.vsix" | Select-Object -First 1 + if (-not $vsixFile) { Write-Error "No VSIX file found in: $root"; exit 1 } + + $vsixPath = $vsixFile.FullName + $manifestPath = Join-Path $root "${{ parameters.manifestName }}" + $signaturePath = Join-Path $root "${{ parameters.signatureName }}" + + Write-Host "VSIX Path: $vsixPath" + Write-Host "Manifest Path: $manifestPath" + Write-Host "Signature Path: $signaturePath" + + if (-not (Test-Path $manifestPath)) { Write-Error "Manifest file not found: $manifestPath"; exit 1 } + if (-not (Test-Path $signaturePath)) { Write-Error "Signature file not found: $signaturePath"; exit 1 } + + Write-Host "Listing platform folder contents:" + Get-ChildItem $root | Select-Object Name,Length | Format-Table -AutoSize + + if ('${{ parameters.preRelease }}' -eq 'True') { + Write-Host 'Publishing as pre-release' + Write-Host "Executing: npx vsce publish --pat *** --packagePath $vsixPath --manifestPath $manifestPath --signaturePath $signaturePath --pre-release" + npx vsce publish --pat $aadToken --packagePath $vsixPath --manifestPath $manifestPath --signaturePath $signaturePath --pre-release + } else { + Write-Host 'Publishing as stable release' + Write-Host "Executing: npx vsce publish --pat *** --packagePath $vsixPath --manifestPath $manifestPath --signaturePath $signaturePath" + npx vsce publish --pat $aadToken --packagePath $vsixPath --manifestPath $manifestPath --signaturePath $signaturePath + } + + if ($LASTEXITCODE -ne 0) { + Write-Error "vsce publish failed for $platformFolder with exit code $LASTEXITCODE" + exit $LASTEXITCODE + } + Write-Host "Successfully published $platformFolder" + + # Step 3: Post-publish summary + - task: PowerShell@2 + displayName: Post-publish summary + inputs: + targetType: inline + script: | + Write-Host 'Published extension artifacts by platform:' + $root = "$(Build.ArtifactStagingDirectory)/${{ parameters.publishFolder }}" + Get-ChildItem $root -Directory | ForEach-Object { + Write-Host "`nPlatform: $($_.Name)" + Get-ChildItem $_.FullName -File | Select-Object Name,Length | Format-Table -AutoSize + } + Write-Host "`nPre-release parameter: ${{ parameters.preRelease }}" diff --git a/build/templates/setup.yml b/build/templates/setup.yml new file mode 100644 index 00000000..4cd0aa80 --- /dev/null +++ b/build/templates/setup.yml @@ -0,0 +1,50 @@ +# DevDiv pipeline setup steps +parameters: + - name: installNode + type: boolean + default: true + - name: installPython + type: boolean + default: true + +steps: + - ${{ if eq(parameters.installNode, true) }}: + - pwsh: | + if (-not (Test-Path '.npmrc')) { + Write-Host 'No .npmrc found, creating one with public npm registry' + @" + # Force public npm registry to avoid CI auth (E401) when no token is provided + registry=https://registry.npmjs.org/ + # Do not require auth for public installs + always-auth=false + "@ | Out-File -FilePath '.npmrc' -Encoding utf8 + } else { + Write-Host '.npmrc already exists' + } + displayName: Ensure .npmrc exists + + - task: npmAuthenticate@0 + inputs: + workingFile: .npmrc + + - script: npm config get registry + displayName: Verify NPM Registry + + - task: NodeTool@0 + inputs: + versionSpec: '22.17.0' + checkLatest: true + displayName: Select Node 22 LTS + + - ${{ if eq(parameters.installPython, true) }}: + - task: PipAuthenticate@1 + displayName: 'Pip Authenticate' + inputs: + artifactFeeds: 'DevDiv/debugpy' + + - task: UsePythonVersion@0 + inputs: + versionSpec: '3.9' # note Install Python dependencies step below relies on Python 3.9 + addToPath: true + architecture: 'x64' + displayName: Select Python version diff --git a/build/templates/sign.yml b/build/templates/sign.yml new file mode 100644 index 00000000..a5201dbb --- /dev/null +++ b/build/templates/sign.yml @@ -0,0 +1,312 @@ +# Template: Sign and validate VS Code extension artifacts +# Usage Example: +# - template: build/templates/sign.yml@self +# parameters: +# buildPlatforms: ${{ parameters.buildPlatforms }} +# workingDirectory: $(Build.StagingDirectory) +# signType: real +# +# Each platform gets its own subfolder to avoid filename collisions +# since all signed VSIX files are named the same (e.g., ms-python.debugpy.vsix) + +parameters: + - name: buildPlatforms + type: object + displayName: 'List of platforms to sign' + - name: workingDirectory + type: string + default: '$(Build.StagingDirectory)' + - name: signType + type: string + default: real + - name: verifySignature + type: boolean + default: true + - name: teamName + type: string + default: VSCode-python-debugger + +steps: + - powershell: | + Write-Host "========================================" + Write-Host "🔧 Sign Template Parameters" + Write-Host "========================================" + Write-Host "Working Directory: ${{ parameters.workingDirectory }}" + Write-Host "Sign Type: ${{ parameters.signType }}" + Write-Host "Verify Signature: ${{ parameters.verifySignature }}" + Write-Host "Team Name: ${{ parameters.teamName }}" + Write-Host "" + Write-Host "📂 Key Paths:" + Write-Host " Pipeline.Workspace: $(Pipeline.Workspace)" + Write-Host " Build.BinariesDirectory: $(Build.BinariesDirectory)" + Write-Host " Build.SourcesDirectory: $(Build.SourcesDirectory)" + Write-Host " Build.StagingDirectory: $(Build.StagingDirectory)" + Write-Host " Build.ArtifactStagingDirectory: $(Build.ArtifactStagingDirectory)" + Write-Host "" + Write-Host "📦 Available artifacts in Build.BinariesDirectory:" + if (Test-Path "$(Build.BinariesDirectory)") { + Get-ChildItem "$(Build.BinariesDirectory)" -Directory -ErrorAction SilentlyContinue | ForEach-Object { + Write-Host " - $($_.Name)" + Get-ChildItem $_.FullName -File -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " $($_.Name) ($($_.Length) bytes)" } + } + } + + Write-Host "📦 Available artifacts in Pipeline.Workspace:" + if (Test-Path "$(Pipeline.Workspace)") { + Get-ChildItem "$(Pipeline.Workspace)" -Directory -ErrorAction SilentlyContinue | ForEach-Object { + Write-Host " - $($_.Name)" + Get-ChildItem $_.FullName -File -ErrorAction SilentlyContinue | ForEach-Object { Write-Host " $($_.Name) ($($_.Length) bytes)" } + } + } + Write-Host "========================================" + displayName: '🔍 Log parameters and environment' + + - task: NuGetToolInstaller@1 + displayName: Install NuGet + + - task: NuGetCommand@2 + displayName: Restore signing packages + inputs: + command: restore + feedsToUse: config + restoreSolution: '$(Build.SourcesDirectory)/packages.config' + restoreDirectory: '$(Build.SourcesDirectory)/packages' + nugetConfigPath: '$(Build.SourcesDirectory)/build/NuGet.config' + + # Setup Node.js and npm authentication + - template: setup.yml@self + + - task: Npm@1 + displayName: 'npm ci (install vsce)' + inputs: + command: ci + workingDir: '$(Build.SourcesDirectory)' + + # ✅ Enable MicroBuildSigningPlugin for PME enforcement (once for all platforms) + - task: MicroBuildSigningPlugin@4 + displayName: Enable MicroBuild Signing + inputs: + signType: ${{ parameters.signType }} + zipSources: false + feedSource: 'https://devdiv.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json' + ConnectedServiceName: 'MicroBuild Signing Task (DevDiv)' + ConnectedPMEServiceName: 6cc74545-d7b9-4050-9dfa-ebefcc8961ea + env: + SYSTEM_ACCESSTOKEN: $(System.AccessToken) + TeamName: ${{ parameters.teamName }} + + # Process each platform in its own subfolder + - ${{ each platform in parameters.buildPlatforms }}: + - powershell: | + Write-Host "========================================" + Write-Host "📦 Setting up platform: ${{ coalesce(platform.vsceTarget, 'universal') }}" + Write-Host "========================================" + + $platformFolder = "${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }}" + Write-Host "📁 Creating platform folder: $platformFolder" + New-Item -ItemType Directory -Path $platformFolder -Force | Out-Null + + $artifactName = "vsix-${{ coalesce(platform.vsceTarget, 'universal') }}" + $artifactPath = "$(Build.BinariesDirectory)/$artifactName" + if (-not (Test-Path $artifactPath)) { + $artifactPath = "$(Pipeline.Workspace)/$artifactName" + } + Write-Host "🔍 Looking for artifact at: $artifactPath" + + if (Test-Path $artifactPath) { + Write-Host "✅ Artifact folder found" + Write-Host "📄 Files in artifact folder:" + Get-ChildItem "$artifactPath" | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" } + + $vsixFiles = Get-ChildItem "$artifactPath/*.vsix" + Write-Host "📦 Found $($vsixFiles.Count) VSIX file(s) to copy" + + foreach ($vsix in $vsixFiles) { + Write-Host " Copying: $($vsix.Name) -> $platformFolder" + Copy-Item $vsix.FullName -Destination $platformFolder -Force + } + Write-Host "✅ Copied VSIX for ${{ coalesce(platform.vsceTarget, 'universal') }}" + + # List what's in the platform folder + Write-Host "" + Write-Host "📂 Contents of platform folder:" + Get-ChildItem $platformFolder | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" } + } else { + Write-Host "❌ Artifact folder not found: $artifactPath" + Write-Host "📂 Contents of Pipeline.Workspace:" + Get-ChildItem "$(Pipeline.Workspace)" | ForEach-Object { Write-Host " - $($_.Name)" } + Write-Error "Artifact folder not found: $artifactPath" + exit 1 + } + Write-Host "========================================" + displayName: "📁 Setup folder for ${{ coalesce(platform.vsceTarget, 'universal') }}" + + - powershell: | + $platformFolder = "${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }}" + $vsixFile = Get-ChildItem "$platformFolder/*.vsix" | Select-Object -First 1 + if ($null -eq $vsixFile) { + Write-Host "##vso[task.logissue type=error]No VSIX file found in $platformFolder" + exit 1 + } + $vsixPath = $vsixFile.FullName + # Use fixed name extension.manifest as expected by sign.proj + $manifestPath = "$platformFolder/extension.manifest" + Write-Host "##vso[task.setvariable variable=VSIX_PATH_${{ coalesce(platform.vsceTarget, 'universal') }}]$vsixPath" + Write-Host "##vso[task.setvariable variable=MANIFEST_PATH_${{ coalesce(platform.vsceTarget, 'universal') }}]$manifestPath" + Write-Host "VSIX: $vsixPath" + Write-Host "Manifest: $manifestPath" + displayName: "🔍 Find VSIX for ${{ coalesce(platform.vsceTarget, 'universal') }}" + + - script: npx vsce generate-manifest -i "$(VSIX_PATH_${{ coalesce(platform.vsceTarget, 'universal') }})" -o "$(MANIFEST_PATH_${{ coalesce(platform.vsceTarget, 'universal') }})" + displayName: "📝 Generate manifest for ${{ coalesce(platform.vsceTarget, 'universal') }}" + + - powershell: | + Write-Host "========================================" + Write-Host "🔍 Pre-sign inspection for: ${{ coalesce(platform.vsceTarget, 'universal') }}" + Write-Host "========================================" + + $platformFolder = "${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }}" + Write-Host "📂 Platform folder: $platformFolder" + Write-Host "" + Write-Host "📄 Files:" + Get-ChildItem $platformFolder | ForEach-Object { + $icon = switch -Wildcard ($_.Extension) { + ".vsix" { "📦" } + ".manifest" { "📝" } + ".p7s" { "🔐" } + default { "📄" } + } + Write-Host " $icon $($_.Name) ($($_.Length) bytes)" + } + + $vsixCount = (Get-ChildItem "$platformFolder/*.vsix").Count + $manifestPath = "$platformFolder/extension.manifest" + Write-Host "" + Write-Host "📊 Summary: $vsixCount VSIX, manifest exists: $(Test-Path $manifestPath)" + + if ($vsixCount -eq 0) { + Write-Host "❌ No VSIX files found" + exit 1 + } + if (!(Test-Path $manifestPath)) { + Write-Host "❌ extension.manifest not found" + exit 1 + } + Write-Host "✅ Ready for signing" + Write-Host "========================================" + displayName: "🔍 Pre-sign inspection for ${{ coalesce(platform.vsceTarget, 'universal') }}" + + - task: MSBuild@1 + displayName: "🔏 Sign ${{ coalesce(platform.vsceTarget, 'universal') }}" + inputs: + solution: '$(Build.SourcesDirectory)/build/sign.proj' + msbuildArguments: > + /verbosity:detailed + /bl:"${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }}/signing.binlog" + /p:SignType=${{ parameters.signType }} + /p:BaseOutputDirectory=${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }} + /p:OutDir=${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }} + /p:IntermediateOutputPath=${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }}/intermediate + + - powershell: | + Write-Host "========================================" + Write-Host "🔍 Post-sign inspection for: ${{ coalesce(platform.vsceTarget, 'universal') }}" + Write-Host "========================================" + + $platformFolder = "${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }}" + Write-Host "📂 Platform folder: $platformFolder" + Write-Host "" + Write-Host "📄 Files after signing:" + Get-ChildItem $platformFolder -File | ForEach-Object { + $icon = switch -Wildcard ($_.Extension) { + ".vsix" { "📦" } + ".manifest" { "📝" } + ".p7s" { "🔐" } + ".binlog" { "📋" } + default { "📄" } + } + Write-Host " $icon $($_.Name) ($($_.Length) bytes)" + } + + $signaturePath = "$platformFolder/extension.signature.p7s" + Write-Host "" + Write-Host "📊 Signature exists: $(Test-Path $signaturePath)" + + if (Test-Path $signaturePath) { + Write-Host "✅ extension.signature.p7s found" + } else { + Write-Host "⚠️ extension.signature.p7s not found after signing" + } + Write-Host "========================================" + displayName: "🔍 Post-sign inspection for ${{ coalesce(platform.vsceTarget, 'universal') }}" + + - powershell: | + Write-Host "========================================" + Write-Host "✅ Validating signature for: ${{ coalesce(platform.vsceTarget, 'universal') }}" + Write-Host "========================================" + + $platformFolder = "${{ parameters.workingDirectory }}/${{ coalesce(platform.vsceTarget, 'universal') }}" + $manifestPath = "$platformFolder/extension.manifest" + $signaturePath = "$platformFolder/extension.signature.p7s" + + Write-Host " Manifest: $manifestPath" + Write-Host " Signature: $signaturePath" + + if (!(Test-Path $manifestPath)) { + Write-Host "❌ Manifest missing" + exit 1 + } + if (!(Test-Path $signaturePath)) { + Write-Host "❌ Signature missing" + exit 1 + } + + $manifestHash = (Get-FileHash -Algorithm SHA256 $manifestPath).Hash + $signatureHash = (Get-FileHash -Algorithm SHA256 $signaturePath).Hash + Write-Host " Manifest SHA256: $manifestHash" + Write-Host " Signature SHA256: $signatureHash" + + if ($manifestHash -eq $signatureHash) { + Write-Host "❌ Signature file is identical to manifest (placeholder detected)" + exit 1 + } else { + Write-Host "✅ Hashes differ - signature is valid" + } + + # Set signature path variable for verify step + Write-Host "##vso[task.setvariable variable=SIGNATURE_PATH_${{ coalesce(platform.vsceTarget, 'universal') }}]$signaturePath" + Write-Host "========================================" + displayName: "✅ Validate signature for ${{ coalesce(platform.vsceTarget, 'universal') }}" + + - ${{ if eq(parameters.verifySignature, true) }}: + - script: npx vsce verify-signature --packagePath "$(VSIX_PATH_${{ coalesce(platform.vsceTarget, 'universal') }})" --manifestPath "$(MANIFEST_PATH_${{ coalesce(platform.vsceTarget, 'universal') }})" --signaturePath "$(SIGNATURE_PATH_${{ coalesce(platform.vsceTarget, 'universal') }})" + displayName: "🔐 Verify signature for ${{ coalesce(platform.vsceTarget, 'universal') }}" + + # Final summary of all signed artifacts + - powershell: | + Write-Host "========================================" + Write-Host "📊 Final Summary - All Signed Platforms" + Write-Host "========================================" + + $baseDir = "${{ parameters.workingDirectory }}" + $platformFolders = Get-ChildItem $baseDir -Directory + + foreach ($folder in $platformFolders) { + Write-Host "" + Write-Host "📁 Platform: $($folder.Name)" + $vsixFiles = Get-ChildItem "$($folder.FullName)/*.vsix" -ErrorAction SilentlyContinue + $signaturePath = "$($folder.FullName)/extension.signature.p7s" + + if ($vsixFiles) { + foreach ($vsix in $vsixFiles) { + $hasSig = Test-Path $signaturePath + $status = if ($hasSig) { "✅ Signed" } else { "❌ Not signed" } + Write-Host " 📦 $($vsix.Name) - $status" + } + } else { + Write-Host " ⚠️ No VSIX files found" + } + } + Write-Host "" + Write-Host "========================================" + displayName: '📊 Final summary' diff --git a/contributing.md b/contributing.md index a4d1f4a9..1d67e193 100644 --- a/contributing.md +++ b/contributing.md @@ -19,7 +19,7 @@ source .venv/bin/activate Install then setup with nox. ``` python3 -m pip install nox -nox --session setup_repo +nox ``` ## Reporting Issues diff --git a/debugpy_info.json b/debugpy_info.json index b24d7ed9..8af314a6 100644 --- a/debugpy_info.json +++ b/debugpy_info.json @@ -1,69 +1,69 @@ { "macOS": [ { - "url": "https://files.pythonhosted.org/packages/3f/32/901c7204cceb3262fdf38f4c25c9a46372c11661e8490e9ea702bc4ff448/debugpy-1.8.13-cp310-cp310-macosx_14_0_x86_64.whl", + "url": "https://files.pythonhosted.org/packages/bf/98/d57054371887f37d3c959a7a8dc3c76b763acb65f5e78d849d7db7cadc5b/debugpy-1.8.19-cp310-cp310-macosx_15_0_x86_64.whl", "hash": { - "sha256": "06859f68e817966723ffe046b896b1bd75c665996a77313370336ee9e1de3e90" + "sha256": "fce6da15d73be5935b4438435c53adb512326a3e11e4f90793ea87cd9f018254" } }, { - "url": "https://files.pythonhosted.org/packages/31/90/dd2fcad8364f0964f476537481985198ce6e879760281ad1cec289f1aa71/debugpy-1.8.13-cp311-cp311-macosx_14_0_universal2.whl", + "url": "https://files.pythonhosted.org/packages/80/e2/48531a609b5a2aa94c6b6853afdfec8da05630ab9aaa96f1349e772119e9/debugpy-1.8.19-cp311-cp311-macosx_15_0_universal2.whl", "hash": { - "sha256": "eee02b2ed52a563126c97bf04194af48f2fe1f68bb522a312b05935798e922ff" + "sha256": "c5dcfa21de1f735a4f7ced4556339a109aa0f618d366ede9da0a3600f2516d8b" } }, { - "url": "https://files.pythonhosted.org/packages/79/ad/dff929b6b5403feaab0af0e5bb460fd723f9c62538b718a9af819b8fff20/debugpy-1.8.13-cp312-cp312-macosx_14_0_universal2.whl", + "url": "https://files.pythonhosted.org/packages/4a/15/d762e5263d9e25b763b78be72dc084c7a32113a0bac119e2f7acae7700ed/debugpy-1.8.19-cp312-cp312-macosx_15_0_universal2.whl", "hash": { - "sha256": "2b8de94c5c78aa0d0ed79023eb27c7c56a64c68217d881bee2ffbcb13951d0c1" + "sha256": "bccb1540a49cde77edc7ce7d9d075c1dbeb2414751bc0048c7a11e1b597a4c2e" } } ], "win64": [ { - "url": "https://files.pythonhosted.org/packages/89/16/1d53a80caf5862627d3eaffb217d4079d7e4a1df6729a2d5153733661efd/debugpy-1.8.13-cp310-cp310-win_amd64.whl", + "url": "https://files.pythonhosted.org/packages/a6/36/7f9053c4c549160c87ae7e43800138f2695578c8b65947114c97250983b6/debugpy-1.8.19-cp310-cp310-win_amd64.whl", "hash": { - "sha256": "dc7b77f5d32674686a5f06955e4b18c0e41fb5a605f5b33cf225790f114cfeec" + "sha256": "b7dd275cf2c99e53adb9654f5ae015f70415bbe2bacbe24cfee30d54b6aa03c5" } }, { - "url": "https://files.pythonhosted.org/packages/cd/d5/3684d7561c8ba2797305cf8259619acccb8d6ebe2117bb33a6897c235eee/debugpy-1.8.13-cp311-cp311-win_amd64.whl", + "url": "https://files.pythonhosted.org/packages/f2/a8/aaac7ff12ddf5d68a39e13a423a8490426f5f661384f5ad8d9062761bd8e/debugpy-1.8.19-cp311-cp311-win_amd64.whl", "hash": { - "sha256": "62f9b4a861c256f37e163ada8cf5a81f4c8d5148fc17ee31fb46813bd658cdcc" + "sha256": "14035cbdbb1fe4b642babcdcb5935c2da3b1067ac211c5c5a8fdc0bb31adbcaa" } }, { - "url": "https://files.pythonhosted.org/packages/c9/f7/0df18a4f530ed3cc06f0060f548efe9e3316102101e311739d906f5650be/debugpy-1.8.13-cp312-cp312-win_amd64.whl", + "url": "https://files.pythonhosted.org/packages/d8/3a/d3d8b48fec96e3d824e404bf428276fb8419dfa766f78f10b08da1cb2986/debugpy-1.8.19-cp312-cp312-win_amd64.whl", "hash": { - "sha256": "63ca7670563c320503fea26ac688988d9d6b9c6a12abc8a8cf2e7dd8e5f6b6ea" + "sha256": "66e3d2fd8f2035a8f111eb127fa508469dfa40928a89b460b41fd988684dc83d" } } ], "linux": [ { - "url": "https://files.pythonhosted.org/packages/95/10/77fe746851c8d84838a807da60c7bd0ac8627a6107d6917dd3293bf8628c/debugpy-1.8.13-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "url": "https://files.pythonhosted.org/packages/ee/dd/c517b9aa3500157a30e4f4c4f5149f880026bd039d2b940acd2383a85d8e/debugpy-1.8.19-cp310-cp310-manylinux_2_34_x86_64.whl", "hash": { - "sha256": "cb56c2db69fb8df3168bc857d7b7d2494fed295dfdbde9a45f27b4b152f37520" + "sha256": "e24b1652a1df1ab04d81e7ead446a91c226de704ff5dde6bd0a0dbaab07aa3f2" } }, { - "url": "https://files.pythonhosted.org/packages/5c/c9/06ff65f15eb30dbdafd45d1575770b842ce3869ad5580a77f4e5590f1be7/debugpy-1.8.13-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "url": "https://files.pythonhosted.org/packages/1b/d4/97775c01d56071969f57d93928899e5616a4cfbbf4c8cc75390d3a51c4a4/debugpy-1.8.19-cp311-cp311-manylinux_2_34_x86_64.whl", "hash": { - "sha256": "4caca674206e97c85c034c1efab4483f33971d4e02e73081265ecb612af65377" + "sha256": "806d6800246244004625d5222d7765874ab2d22f3ba5f615416cf1342d61c488" } }, { - "url": "https://files.pythonhosted.org/packages/d6/4f/b7d42e6679f0bb525888c278b0c0d2b6dff26ed42795230bb46eaae4f9b3/debugpy-1.8.13-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", + "url": "https://files.pythonhosted.org/packages/a7/88/f7d25c68b18873b7c53d7c156ca7a7ffd8e77073aa0eac170a9b679cf786/debugpy-1.8.19-cp312-cp312-manylinux_2_34_x86_64.whl", "hash": { - "sha256": "887d54276cefbe7290a754424b077e41efa405a3e07122d8897de54709dbe522" + "sha256": "e9c68d9a382ec754dc05ed1d1b4ed5bd824b9f7c1a8cd1083adb84b3c93501de" } } ], "any": [ { - "url": "https://files.pythonhosted.org/packages/37/4f/0b65410a08b6452bfd3f7ed6f3610f1a31fb127f46836e82d31797065dcb/debugpy-1.8.13-py2.py3-none-any.whl", + "url": "https://files.pythonhosted.org/packages/25/3e/e27078370414ef35fafad2c06d182110073daaeb5d3bf734b0b1eeefe452/debugpy-1.8.19-py2.py3-none-any.whl", "hash": { - "sha256": "d4ba115cdd0e3a70942bd562adba9ec8c651fe69ddde2298a1be296fc331906f" + "sha256": "360ffd231a780abbc414ba0f005dad409e71c78637efe8f2bd75837132a41d38" } } ] diff --git a/noxfile.py b/noxfile.py index 0d89c14a..cd935d58 100644 --- a/noxfile.py +++ b/noxfile.py @@ -8,6 +8,7 @@ import os import pathlib import re +import tempfile import urllib.request as url_lib import zipfile @@ -65,15 +66,98 @@ def install_bundled_libs(session): target = os.environ.get("VSCETARGET", "") print("target:", target) if "darwin" in target: - download_url(debugpy_info["macOS"]) + wheels = debugpy_info["macOS"] elif "win32-ia32" == target: - download_url(debugpy_info["win32"]) + wheels = debugpy_info.get("win32", debugpy_info["any"]) elif "win32-x64" == target: - download_url(debugpy_info["win64"]) + wheels = debugpy_info["win64"] elif "linux-x64" == target: - download_url(debugpy_info["linux"]) + wheels = debugpy_info["linux"] else: - download_url(debugpy_info["any"]) + wheels = debugpy_info["any"] + + download_debugpy_via_pip(session, wheels) + + +def _parse_wheel_info(url: str) -> dict: + """Parse version and platform info from a wheel URL. + + Example URL: .../debugpy-1.8.19-cp311-cp311-win_amd64.whl + Returns: {"version": "1.8.19", "py_ver": "311", "abi": "cp311", "platform": "win_amd64"} + """ + filename = url.rsplit("/", 1)[-1] + # Wheel filename format: {name}-{version}-{python}-{abi}-{platform}.whl + match = re.match(r"debugpy-([^-]+)-cp(\d+)-([^-]+)-(.+)\.whl", filename) + if match: + return { + "version": match.group(1), + "py_ver": match.group(2), + "abi": match.group(3), + "platform": match.group(4), + } + # Fallback for py2.py3-none-any wheels + match = re.match(r"debugpy-([^-]+)-py\d\.py\d-none-any\.whl", filename) + if match: + return { + "version": match.group(1), + "py_ver": None, + "abi": "none", + "platform": "any", + } + raise ValueError(f"Could not parse wheel filename: {filename}") + + +def download_debugpy_via_pip(session: nox.Session, wheels: list) -> None: + """Downloads debugpy wheels via pip and extracts them into bundled/libs. + + Uses pip to download by package name, allowing pip to use configured + index URLs (e.g., Azure Artifacts feed) instead of direct PyPI URLs. + """ + libs_dir = pathlib.Path.cwd() / "bundled" / "libs" + libs_dir.mkdir(parents=True, exist_ok=True) + + # Parse version and platform info from wheel URLs + parsed = [_parse_wheel_info(w["url"]) for w in wheels] + version = parsed[0]["version"] + + with tempfile.TemporaryDirectory(prefix="debugpy_wheels_") as tmp_dir: + tmp_path = pathlib.Path(tmp_dir) + + for info in parsed: + args = [ + "python", + "-m", + "pip", + "download", + f"debugpy=={version}", + "--no-deps", + "--only-binary", + ":all:", + "--dest", + str(tmp_path), + ] + if info["py_ver"]: + # Platform-specific wheel + args.extend(["--python-version", info["py_ver"]]) + args.extend(["--implementation", "cp"]) + args.extend(["--abi", info["abi"]]) + args.extend(["--platform", info["platform"]]) + # For none-any wheels, no platform args needed + + session.run(*args) + + wheel_paths = sorted(tmp_path.glob("debugpy-*.whl")) + if not wheel_paths: + raise FileNotFoundError( + f"pip download produced no debugpy wheels for version {version}." + ) + + for wheel_path in wheel_paths: + print("Downloaded:", wheel_path.name) + with zipfile.ZipFile(wheel_path, "r") as wheel: + for zip_info in wheel.infolist(): + print("\t" + zip_info.filename) + wheel.extract(zip_info.filename, libs_dir) def download_url(values): diff --git a/package-lock.json b/package-lock.json index 04d911ac..2cbce9b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,39 +1,39 @@ { "name": "debugpy", - "version": "2025.9.0-dev", + "version": "2025.19.0-dev", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "debugpy", - "version": "2025.9.0-dev", + "version": "2025.19.0-dev", "license": "MIT", "dependencies": { "@vscode/debugadapter": "^1.65.0", "@vscode/debugprotocol": "^1.65.0", - "@vscode/extension-telemetry": "^0.8.5", - "@vscode/python-extension": "^1.0.5", + "@vscode/extension-telemetry": "^0.8.4", + "@vscode/python-extension": "^1.0.6", "fs-extra": "^11.2.0", "iconv-lite": "^0.6.3", - "jsonc-parser": "^3.2.0", + "jsonc-parser": "^3.0.0", "lodash": "^4.17.21", "vscode-languageclient": "^8.0.2" }, "devDependencies": { - "@types/chai": "^4.3.4", - "@types/chai-as-promised": "^7.1.8", + "@types/chai": "^4.1.2", + "@types/chai-as-promised": "^7.1.0", "@types/fs-extra": "^11.0.4", "@types/glob": "^7.2.0", - "@types/lodash": "^4.14.191", - "@types/mocha": "^10.0.7", - "@types/node": "18.x", - "@types/semver": "^7.3.13", + "@types/lodash": "^4.14.104", + "@types/mocha": "^9.1.0", + "@types/node": "^22.5.0", + "@types/semver": "^5.5.0", "@types/sinon": "^10.0.13", "@types/vscode": "^1.87.0", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "@vscode/test-electron": "^2.3.9", - "@vscode/vsce": "^2.24.0", + "@vscode/vsce": "^3.7.1-1", "chai": "^4.3.7", "chai-as-promised": "^7.1.1", "eslint": "^8.50.0", @@ -46,8 +46,8 @@ "ts-mockito": "^2.6.1", "typemoq": "^2.1.0", "typescript": "^5.5.4", - "webpack": "^5.87.0", - "webpack-cli": "^5.1.4" + "webpack": "^5.76.0", + "webpack-cli": "^4.9.2" }, "engines": { "vscode": "^1.92.0" @@ -62,6 +62,23 @@ "node": ">=0.10.0" } }, + "node_modules/@azu/format-text": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", + "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@azu/style-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", + "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "@azu/format-text": "^1.0.1" + } + }, "node_modules/@azure/abort-controller": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", @@ -74,16 +91,84 @@ } }, "node_modules/@azure/core-auth": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", - "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", + "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", + "license": "MIT", "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-util": "^1.1.0", + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz", + "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/core-rest-pipeline": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz", + "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" } }, "node_modules/@azure/core-rest-pipeline": { @@ -139,14 +224,15 @@ } }, "node_modules/@azure/core-tracing": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", - "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz", + "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==", + "license": "MIT", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" } }, "node_modules/@azure/core-util": { @@ -172,15 +258,112 @@ "node": ">=12.0.0" } }, + "node_modules/@azure/identity": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.0.tgz", + "integrity": "sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^4.2.0", + "@azure/msal-node": "^3.5.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/identity/node_modules/@azure/core-rest-pipeline": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz", + "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/identity/node_modules/@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@azure/logger": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.3.tgz", - "integrity": "sha512-J8/cIKNQB1Fc9fuYqBVnrppiUtW+5WWJPCj/tAokC5LdSTwkWWttN+jsRgw9BLYD7JDBx7PceiqOBxJJ1tQz3Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", + "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==", + "license": "MIT", "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=18.0.0" + "node": ">=20.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.27.0.tgz", + "integrity": "sha512-bZ8Pta6YAbdd0o0PEaL1/geBsPrLEnyY/RDWqvF1PP9RUH8EMLvUMGoZFYS6jSlUan6KZ9IMTLCnwpWWpQRK/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "15.13.3" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "15.13.3", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.3.tgz", + "integrity": "sha512-shSDU7Ioecya+Aob5xliW9IGq1Ui8y4EVSdWGyI1Gbm4Vg61WpP95LuzcY214/wEjSn6w4PZYD4/iVldErHayQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.4.tgz", + "integrity": "sha512-lvuAwsDpPDE/jSuVQOBMpLbXuVuLsPNRwWCyK3/6bPlBk0fGWegqoZ0qjZclMWyQ2JNvIY3vHY7hoFmFmFQcOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "15.13.3", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=16" } }, "node_modules/@azure/opentelemetry-instrumentation-azure-sdk": { @@ -199,6 +382,31 @@ "node": ">=14.0.0" } }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -297,6 +505,132 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -570,62 +904,363 @@ "node": ">=14" } }, - "node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "node_modules/@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", "dev": true, + "license": "MIT", "dependencies": { - "type-detect": "4.0.8" + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz", - "integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==", + "node_modules/@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", "dev": true, + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" + }, + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "node_modules/@secretlint/config-loader/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "license": "MIT", "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "node_modules/@secretlint/config-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", "dev": true, + "license": "MIT", "dependencies": { - "type-detect": "4.0.8" + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" } }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "dev": true + "node_modules/@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "node_modules/@secretlint/formatter/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "node_modules/@secretlint/formatter/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@secretlint/formatter/node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-sarif-builder": "^3.2.0" + } + }, + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz", + "integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "dev": true + }, + "node_modules/@textlint/ast-node-types": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.5.0.tgz", + "integrity": "sha512-K0LEuuTo4rza8yDrlYkRdXLao8Iz/QBMsQdIxRrOOrLYb4HAtZaypZ78c+J6rDA1UlGxadZVLmkkiv4KV5fMKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.5.0.tgz", + "integrity": "sha512-DPTm2+VXKID41qKQWagg/4JynM6hEEpvbq0PlGsEoC4Xm7IqXIxFym3mSf5+ued0cuiIV1hR9kgXjqGdP035tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azu/format-text": "^1.0.2", + "@azu/style-format": "^1.0.1", + "@textlint/module-interop": "15.5.0", + "@textlint/resolver": "15.5.0", + "@textlint/types": "15.5.0", + "chalk": "^4.1.2", + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "lodash": "^4.17.21", + "pluralize": "^2.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "table": "^6.9.0", + "text-table": "^0.2.0" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/pluralize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/module-interop": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.5.0.tgz", + "integrity": "sha512-rqfouEhBEgZlR9umswWXXRBcmmSM28Trpr9b0duzgehKYVc7wSQCuQMagr6YBJa2NRMfRNinupusbJXMg0ij2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/resolver": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.5.0.tgz", + "integrity": "sha512-kK5nFbg5N3kVoZExQI/dnYjCInmTltvXDnuCRrBxHI01i6kO/o8R7Lc2aFkAZ6/NUZuRPalkyDdwZJke4/R2wg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/types": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.5.0.tgz", + "integrity": "sha512-EjAPbuA+3NyQ9WyFP7iUlddi35F3mGrf4tb4cZM0nWywbtEJ3+XAYqL+5RsF0qFeSguxGir09NdZOWrG9wVOUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.5.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/chai": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", "dev": true }, @@ -692,22 +1327,42 @@ "dev": true }, "node_modules/@types/mocha": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.7.tgz", - "integrity": "sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==", - "dev": true + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "18.18.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.3.tgz", - "integrity": "sha512-0OVfGupTl3NBFr8+iXpfZ8NR7jfFO+P1Q+IO/q0wbo02wYkP5gy36phojeYWpLQ6WAMjl+VfmqUk2YbUfp0irA==", - "dev": true + "version": "22.17.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.1.tgz", + "integrity": "sha512-y3tBaz+rjspDTylNjAX37jEC3TETEFGNJL6uQDxwF9/8GLLIjW1rvVHlynyuUKMnMr1Roq8jOv3vkopBjC4/VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", - "dev": true + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/shimmer": { "version": "1.2.0", @@ -906,6 +1561,13 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/@typescript-eslint/utils/node_modules/@types/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/visitor-keys": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", @@ -923,6 +1585,55 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.2.tgz", + "integrity": "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==", + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@vscode/debugadapter": { "version": "1.65.0", "resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.65.0.tgz", @@ -996,12 +1707,13 @@ "integrity": "sha512-gNw9z9LbqLV+WadZ6/MMrWwO3e0LuoUH1wve/1iPsBNbgqeVCiB0EZFNNj2lysxS2gkqoF9hmyVaG3MoM1BkxA==" }, "node_modules/@vscode/python-extension": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@vscode/python-extension/-/python-extension-1.0.5.tgz", - "integrity": "sha512-uYhXUrL/gn92mfqhjAwH2+yGOpjloBxj9ekoL4BhUsKcyJMpEg6WlNf3S3si+5x9zlbHHe7FYQNjZEbz1ymI9Q==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@vscode/python-extension/-/python-extension-1.0.6.tgz", + "integrity": "sha512-q7KYf+mymM67G0yS6xfhczFwu2teBi5oXHVdNgtCsYhErdSOkwMPtE291SqQahrjTcgKxn7O56i1qb1EQR6o4w==", + "license": "MIT", "engines": { - "node": ">=16.17.1", - "vscode": "^1.78.0" + "node": ">=22.17.0", + "vscode": "^1.93.0" } }, "node_modules/@vscode/test-electron": { @@ -1020,26 +1732,36 @@ } }, "node_modules/@vscode/vsce": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.24.0.tgz", - "integrity": "sha512-p6CIXpH5HXDqmUkgFXvIKTjZpZxy/uDx4d/UsfhS9vQUun43KDNUbYeZocyAHgqcJlPEurgArHz9te1PPiqPyA==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.7.1.tgz", + "integrity": "sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g==", "dev": true, + "license": "MIT", "dependencies": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", + "@azure/identity": "^4.1.0", + "@secretlint/node": "^10.1.2", + "@secretlint/secretlint-formatter-sarif": "^10.1.2", + "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", + "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", + "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.9", - "commander": "^6.2.1", - "glob": "^7.0.6", + "cockatiel": "^3.1.2", + "commander": "^12.1.0", + "form-data": "^4.0.0", + "glob": "^11.0.0", "hosted-git-info": "^4.0.2", "jsonc-parser": "^3.2.0", "leven": "^3.1.0", - "markdown-it": "^12.3.2", + "markdown-it": "^14.1.0", "mime": "^1.3.4", "minimatch": "^3.0.3", "parse-semver": "^1.1.1", "read": "^1.0.7", + "secretlint": "^10.1.2", "semver": "^7.5.2", - "tmp": "^0.2.1", + "tmp": "^0.2.3", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", "xml2js": "^0.5.0", @@ -1050,53 +1772,218 @@ "vsce": "vsce" }, "engines": { - "node": ">= 14" + "node": ">= 20" }, "optionalDependencies": { "keytar": "^7.7.0" } }, - "node_modules/@vscode/vsce/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/@vscode/vsce-sign": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.9.tgz", + "integrity": "sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g==", "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optionalDependencies": { + "@vscode/vsce-sign-alpine-arm64": "2.0.6", + "@vscode/vsce-sign-alpine-x64": "2.0.6", + "@vscode/vsce-sign-darwin-arm64": "2.0.6", + "@vscode/vsce-sign-darwin-x64": "2.0.6", + "@vscode/vsce-sign-linux-arm": "2.0.6", + "@vscode/vsce-sign-linux-arm64": "2.0.6", + "@vscode/vsce-sign-linux-x64": "2.0.6", + "@vscode/vsce-sign-win32-arm64": "2.0.6", + "@vscode/vsce-sign-win32-x64": "2.0.6" + } + }, + "node_modules/@vscode/vsce-sign-alpine-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", + "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" - } + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", - "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "node_modules/@vscode/vsce-sign-alpine-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", + "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "node_modules/@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", + "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", + "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", + "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", + "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", + "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-win32-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", + "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce-sign-win32-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", + "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce/node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/vsce/node_modules/glob/node_modules/minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", "dev": true, "license": "MIT" @@ -1237,42 +2124,37 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", "dev": true, - "engines": { - "node": ">=14.15.0" - }, + "license": "MIT", "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" } }, "node_modules/@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", "dev": true, - "engines": { - "node": ">=14.15.0" + "license": "MIT", + "dependencies": { + "envinfo": "^7.7.3" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack-cli": "4.x.x" } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", "dev": true, - "engines": { - "node": ">=14.15.0" - }, + "license": "MIT", "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack-cli": "4.x.x" }, "peerDependenciesMeta": { "webpack-dev-server": { @@ -1377,6 +2259,22 @@ "node": ">=6" } }, + "node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -1387,15 +2285,19 @@ } }, "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { @@ -1466,6 +2368,16 @@ "node": "<=0.11.8 || >0.11.10" } }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/async-hook-jl": { "version": "1.7.6", "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", @@ -1503,10 +2415,11 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/azure-devops-node-api": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", - "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", "dev": true, + "license": "MIT", "dependencies": { "tunnel": "0.0.6", "typed-rest-client": "^1.8.4" @@ -1547,6 +2460,22 @@ "node": ">=8" } }, + "node_modules/binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -1605,11 +2534,19 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1675,6 +2612,13 @@ "node": "*" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -1682,17 +2626,44 @@ "dev": true, "license": "MIT" }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -1774,17 +2745,20 @@ } }, "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/check-error": { @@ -1947,20 +2921,35 @@ "semver": "bin/semver" } }, + "node_modules/cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "1.1.3" + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", @@ -1980,12 +2969,13 @@ } }, "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=18" } }, "node_modules/concat-map": { @@ -2053,11 +3043,12 @@ } }, "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2124,21 +3115,47 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/default-browser": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", "dev": true, + "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/delayed-stream": { @@ -2263,18 +3280,66 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, - "node_modules/electron-to-chromium": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", - "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", - "dev": true - }, - "node_modules/emitter-listener": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", - "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", "dependencies": { - "shimmer": "^1.2.0" + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==", + "dev": true + }, + "node_modules/emitter-listener": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.2.tgz", + "integrity": "sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ==", + "dependencies": { + "shimmer": "^1.2.0" } }, "node_modules/emoji-regex": { @@ -2320,10 +3385,11 @@ } }, "node_modules/envinfo": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.9.0.tgz", - "integrity": "sha512-RODB4txU+xImYDemN5DqaKC0CHk05XSVkOX4pq0hK26Qx+1LChkuOyUDlGEjYb3ACr0n9qBhFjg37hQuJvpkRQ==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", "dev": true, + "license": "MIT", "bin": { "envinfo": "dist/cli.js" }, @@ -2331,14 +3397,24 @@ "node": ">=4" } }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" + "license": "MIT", + "engines": { + "node": ">=18" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -2347,7 +3423,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -2358,6 +3433,33 @@ "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", "dev": true }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -2368,15 +3470,6 @@ "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/eslint": { "version": "8.50.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", @@ -2456,55 +3549,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/eslint/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -2542,27 +3586,6 @@ "node": ">=4.0" } }, - "node_modules/eslint/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/eslint/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -2666,16 +3689,17 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -2705,6 +3729,23 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -2800,13 +3841,33 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -2880,16 +3941,21 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -2898,6 +3964,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -2944,10 +4023,11 @@ "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -3000,12 +4080,12 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3023,31 +4103,20 @@ "dev": true }, "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -3055,11 +4124,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -3246,6 +4318,19 @@ "node": ">=0.8.19" } }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3270,12 +4355,13 @@ "optional": true }, "node_modules/interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">= 0.10" } }, "node_modules/is-binary-path": { @@ -3304,6 +4390,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -3334,6 +4436,25 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -3385,9 +4506,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, @@ -3406,6 +4543,40 @@ "node": ">=0.10.0" } }, + "node_modules/istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -3421,16 +4592,6 @@ "node": ">= 10.13.0" } }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -3447,10 +4608,17 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "dependencies": { "argparse": "^2.0.1" @@ -3477,6 +4645,19 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", @@ -3493,6 +4674,29 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -3511,6 +4715,29 @@ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", "dev": true }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keytar": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", @@ -3564,12 +4791,13 @@ } }, "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, + "license": "MIT", "dependencies": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, "node_modules/loader-runner": { @@ -3607,12 +4835,68 @@ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -3629,76 +4913,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-symbols/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/log-symbols/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/log-symbols/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/log-symbols/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/log-symbols/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/loupe": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", @@ -3720,35 +4934,38 @@ } }, "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, "bin": { - "markdown-it": "bin/markdown-it.js" + "markdown-it": "bin/markdown-it.mjs" } }, - "node_modules/markdown-it/node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", @@ -3846,6 +5063,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -3889,10 +5116,11 @@ } }, "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -3909,15 +5137,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/mocha/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -3930,12 +5149,6 @@ "node": ">=10" } }, - "node_modules/mocha/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -3957,9 +5170,10 @@ "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/mute-stream": { "version": "0.0.8", @@ -4040,6 +5254,55 @@ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4062,10 +5325,14 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4079,6 +5346,25 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -4126,15 +5412,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -4153,6 +5459,37 @@ "node": ">=6" } }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/parse-semver": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", @@ -4228,6 +5565,33 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/path-to-regexp": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", @@ -4269,10 +5633,11 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", - "dev": true + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4350,6 +5715,16 @@ "node": ">=8" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/postinstall-build": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/postinstall-build/-/postinstall-build-5.0.3.tgz", @@ -4428,13 +5803,24 @@ "once": "^1.3.1" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -4488,6 +5874,19 @@ "rc": "cli.js" } }, + "node_modules/rc-config-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + } + }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -4510,6 +5909,39 @@ "node": ">=0.8" } }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -4538,15 +5970,16 @@ } }, "node_modules/rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, + "license": "MIT", "dependencies": { - "resolve": "^1.20.0" + "resolve": "^1.9.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 0.10" } }, "node_modules/require-directory": { @@ -4558,6 +5991,16 @@ "node": ">=0.10.0" } }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-in-the-middle": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.3.0.tgz", @@ -4662,6 +6105,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -4721,6 +6177,98 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/secretlint": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz", + "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-creator": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/node": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "debug": "^4.4.1", + "globby": "^14.1.0", + "read-pkg": "^9.0.1" + }, + "bin": { + "secretlint": "bin/secretlint.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/secretlint/node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/secretlint/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/secretlint/node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/secretlint/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/secretlint/node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -4744,23 +6292,6 @@ "randombytes": "^2.1.0" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -4806,19 +6337,94 @@ "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -4884,34 +6490,31 @@ "url": "https://opencollective.com/sinon" } }, - "node_modules/sinon/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/sinon/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/source-map": { @@ -4935,6 +6538,42 @@ "source-map": "^0.6.0" } }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/stack-chain": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", @@ -4963,6 +6602,22 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -4975,6 +6630,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4987,16 +6656,44 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.0.0" + } + }, "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -5010,6 +6707,47 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -5020,11 +6758,10 @@ } }, "node_modules/tar-fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", - "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "dev": true, - "license": "MIT", "optional": true, "dependencies": { "chownr": "^1.1.1", @@ -5065,6 +6802,23 @@ "node": ">= 6" } }, + "node_modules/terminal-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz", + "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^3.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/terser": { "version": "5.31.6", "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", @@ -5132,117 +6886,60 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-loader": { - "version": "9.4.3", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.3.tgz", - "integrity": "sha512-n3hBnm6ozJYzwiwt5YRiJZkzktftRpMiBApHaJPoWLA+qetQBAXkHqCLM6nwSdRDimqVtA5ocIkcTRLMTt7yzA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "enhanced-resolve": "^5.0.0", - "micromatch": "^4.0.0", - "semver": "^7.3.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", "dev": true, + "license": "Artistic-2.0", "dependencies": { - "color-convert": "^2.0.1" + "editions": "^6.21.0" }, "engines": { - "node": ">=8" + "node": ">=4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://bevry.me/fund" } }, - "node_modules/ts-loader/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/tmp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", + "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=14.14" } }, - "node_modules/ts-loader/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" + "is-number": "^7.0.0" }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ts-loader/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/ts-loader/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=8.0" } }, - "node_modules/ts-loader/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/ts-loader": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.3.tgz", + "integrity": "sha512-n3hBnm6ozJYzwiwt5YRiJZkzktftRpMiBApHaJPoWLA+qetQBAXkHqCLM6nwSdRDimqVtA5ocIkcTRLMTt7yzA==", "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" }, "engines": { - "node": ">=8" + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" } }, "node_modules/ts-mockito": { @@ -5285,6 +6982,7 @@ "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } @@ -5336,10 +7034,11 @@ } }, "node_modules/typed-rest-client": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", - "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", "dev": true, + "license": "MIT", "dependencies": { "qs": "^6.9.1", "tunnel": "0.0.6", @@ -5375,16 +7074,38 @@ } }, "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" }, "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", - "dev": true + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/universalify": { "version": "2.0.0", @@ -5463,6 +7184,30 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/vscode-jsonrpc": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", @@ -5485,9 +7230,10 @@ } }, "node_modules/vscode-languageclient/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -5579,42 +7325,45 @@ } }, "node_modules/webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", "dev": true, + "license": "MIT", "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", "colorette": "^2.0.14", - "commander": "^10.0.1", + "commander": "^7.0.0", "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", "webpack-merge": "^5.7.3" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=14.15.0" + "node": ">=10.13.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "5.x.x" + "webpack": "4.x.x || 5.x.x" }, "peerDependenciesMeta": { "@webpack-cli/generators": { "optional": true }, + "@webpack-cli/migrate": { + "optional": true + }, "webpack-bundle-analyzer": { "optional": true }, @@ -5624,12 +7373,13 @@ } }, "node_modules/webpack-cli/node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=14" + "node": ">= 10" } }, "node_modules/webpack-merge": { @@ -5698,45 +7448,47 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xml2js": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", @@ -5854,6 +7606,21 @@ "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", "dev": true }, + "@azu/format-text": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", + "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", + "dev": true + }, + "@azu/style-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", + "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", + "dev": true, + "requires": { + "@azu/format-text": "^1.0.1" + } + }, "@azure/abort-controller": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", @@ -5863,13 +7630,68 @@ } }, "@azure/core-auth": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", - "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", + "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", "requires": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-util": "^1.1.0", + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "requires": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + } + } + } + }, + "@azure/core-client": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz", + "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==", + "dev": true, + "requires": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", "tslib": "^2.6.2" + }, + "dependencies": { + "@azure/core-rest-pipeline": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz", + "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==", + "dev": true, + "requires": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + } + }, + "@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "dev": true, + "requires": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + } + } } }, "@azure/core-rest-pipeline": { @@ -5915,9 +7737,9 @@ } }, "@azure/core-tracing": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", - "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz", + "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==", "requires": { "tslib": "^2.6.2" } @@ -5941,14 +7763,88 @@ } } }, + "@azure/identity": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.0.tgz", + "integrity": "sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==", + "dev": true, + "requires": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^4.2.0", + "@azure/msal-node": "^3.5.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "dependencies": { + "@azure/core-rest-pipeline": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz", + "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==", + "dev": true, + "requires": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + } + }, + "@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "dev": true, + "requires": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + } + } + } + }, "@azure/logger": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.3.tgz", - "integrity": "sha512-J8/cIKNQB1Fc9fuYqBVnrppiUtW+5WWJPCj/tAokC5LdSTwkWWttN+jsRgw9BLYD7JDBx7PceiqOBxJJ1tQz3Q==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", + "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==", "requires": { + "@typespec/ts-http-runtime": "^0.3.0", "tslib": "^2.6.2" } }, + "@azure/msal-browser": { + "version": "4.27.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.27.0.tgz", + "integrity": "sha512-bZ8Pta6YAbdd0o0PEaL1/geBsPrLEnyY/RDWqvF1PP9RUH8EMLvUMGoZFYS6jSlUan6KZ9IMTLCnwpWWpQRK/w==", + "dev": true, + "requires": { + "@azure/msal-common": "15.13.3" + } + }, + "@azure/msal-common": { + "version": "15.13.3", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.3.tgz", + "integrity": "sha512-shSDU7Ioecya+Aob5xliW9IGq1Ui8y4EVSdWGyI1Gbm4Vg61WpP95LuzcY214/wEjSn6w4PZYD4/iVldErHayQ==", + "dev": true + }, + "@azure/msal-node": { + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.4.tgz", + "integrity": "sha512-lvuAwsDpPDE/jSuVQOBMpLbXuVuLsPNRwWCyK3/6bPlBk0fGWegqoZ0qjZclMWyQ2JNvIY3vHY7hoFmFmFQcOw==", + "dev": true, + "requires": { + "@azure/msal-common": "15.13.3", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + } + }, "@azure/opentelemetry-instrumentation-azure-sdk": { "version": "1.0.0-beta.5", "resolved": "https://registry.npmjs.org/@azure/opentelemetry-instrumentation-azure-sdk/-/opentelemetry-instrumentation-azure-sdk-1.0.0-beta.5.tgz", @@ -5962,6 +7858,23 @@ "tslib": "^2.2.0" } }, + "@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true + }, "@discoveryjs/json-ext": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", @@ -6017,18 +7930,98 @@ "minimatch": "^3.0.5" } }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true - }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true + }, + "@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "requires": { + "@isaacs/balanced-match": "^4.0.1" + } + }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -6238,6 +8231,177 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==" }, + "@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", + "dev": true, + "requires": { + "@secretlint/types": "^10.2.2" + } + }, + "@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", + "dev": true, + "requires": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", + "dev": true, + "requires": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + } + }, + "@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", + "dev": true, + "requires": { + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true + }, + "chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true + }, + "strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", + "dev": true, + "requires": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + } + }, + "@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "dev": true + }, + "@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "dev": true + }, + "@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "dev": true, + "requires": { + "node-sarif-builder": "^3.2.0" + } + }, + "@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "dev": true, + "requires": { + "@secretlint/types": "^10.2.2" + } + }, + "@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "dev": true + }, + "@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "dev": true, + "requires": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + } + }, + "@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "dev": true + }, + "@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true + }, "@sinonjs/commons": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", @@ -6284,6 +8448,63 @@ "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", "dev": true }, + "@textlint/ast-node-types": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.5.0.tgz", + "integrity": "sha512-K0LEuuTo4rza8yDrlYkRdXLao8Iz/QBMsQdIxRrOOrLYb4HAtZaypZ78c+J6rDA1UlGxadZVLmkkiv4KV5fMKQ==", + "dev": true + }, + "@textlint/linter-formatter": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.5.0.tgz", + "integrity": "sha512-DPTm2+VXKID41qKQWagg/4JynM6hEEpvbq0PlGsEoC4Xm7IqXIxFym3mSf5+ued0cuiIV1hR9kgXjqGdP035tw==", + "dev": true, + "requires": { + "@azu/format-text": "^1.0.2", + "@azu/style-format": "^1.0.1", + "@textlint/module-interop": "15.5.0", + "@textlint/resolver": "15.5.0", + "@textlint/types": "15.5.0", + "chalk": "^4.1.2", + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "lodash": "^4.17.21", + "pluralize": "^2.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "table": "^6.9.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "pluralize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", + "dev": true + } + } + }, + "@textlint/module-interop": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.5.0.tgz", + "integrity": "sha512-rqfouEhBEgZlR9umswWXXRBcmmSM28Trpr9b0duzgehKYVc7wSQCuQMagr6YBJa2NRMfRNinupusbJXMg0ij2A==", + "dev": true + }, + "@textlint/resolver": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.5.0.tgz", + "integrity": "sha512-kK5nFbg5N3kVoZExQI/dnYjCInmTltvXDnuCRrBxHI01i6kO/o8R7Lc2aFkAZ6/NUZuRPalkyDdwZJke4/R2wg==", + "dev": true + }, + "@textlint/types": { + "version": "15.5.0", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.5.0.tgz", + "integrity": "sha512-EjAPbuA+3NyQ9WyFP7iUlddi35F3mGrf4tb4cZM0nWywbtEJ3+XAYqL+5RsF0qFeSguxGir09NdZOWrG9wVOUQ==", + "dev": true, + "requires": { + "@textlint/ast-node-types": "15.5.0" + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -6359,21 +8580,36 @@ "dev": true }, "@types/mocha": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.7.tgz", - "integrity": "sha512-GN8yJ1mNTcFcah/wKEFIJckJx9iJLoMSzWcfRRuxz/Jk+U6KQNnml+etbtxFK8lPjzOw3zp4Ha/kjSst9fsHYw==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", "dev": true }, "@types/node": { - "version": "18.18.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.3.tgz", - "integrity": "sha512-0OVfGupTl3NBFr8+iXpfZ8NR7jfFO+P1Q+IO/q0wbo02wYkP5gy36phojeYWpLQ6WAMjl+VfmqUk2YbUfp0irA==", + "version": "22.17.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.1.tgz", + "integrity": "sha512-y3tBaz+rjspDTylNjAX37jEC3TETEFGNJL6uQDxwF9/8GLLIjW1rvVHlynyuUKMnMr1Roq8jOv3vkopBjC4/VA==", + "dev": true, + "requires": { + "undici-types": "~6.21.0" + } + }, + "@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", "dev": true }, "@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", "dev": true }, "@types/shimmer": { @@ -6489,6 +8725,14 @@ "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" + }, + "dependencies": { + "@types/semver": { + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", + "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", + "dev": true + } } }, "@typescript-eslint/visitor-keys": { @@ -6501,6 +8745,41 @@ "eslint-visitor-keys": "^3.3.0" } }, + "@typespec/ts-http-runtime": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.2.tgz", + "integrity": "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==", + "requires": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "dependencies": { + "agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==" + }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "requires": { + "agent-base": "^7.1.2", + "debug": "4" + } + } + } + }, "@vscode/debugadapter": { "version": "1.65.0", "resolved": "https://registry.npmjs.org/@vscode/debugadapter/-/debugadapter-1.65.0.tgz", @@ -6567,9 +8846,9 @@ } }, "@vscode/python-extension": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@vscode/python-extension/-/python-extension-1.0.5.tgz", - "integrity": "sha512-uYhXUrL/gn92mfqhjAwH2+yGOpjloBxj9ekoL4BhUsKcyJMpEg6WlNf3S3si+5x9zlbHHe7FYQNjZEbz1ymI9Q==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@vscode/python-extension/-/python-extension-1.0.6.tgz", + "integrity": "sha512-q7KYf+mymM67G0yS6xfhczFwu2teBi5oXHVdNgtCsYhErdSOkwMPtE291SqQahrjTcgKxn7O56i1qb1EQR6o4w==" }, "@vscode/test-electron": { "version": "2.3.9", @@ -6584,27 +8863,36 @@ } }, "@vscode/vsce": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.24.0.tgz", - "integrity": "sha512-p6CIXpH5HXDqmUkgFXvIKTjZpZxy/uDx4d/UsfhS9vQUun43KDNUbYeZocyAHgqcJlPEurgArHz9te1PPiqPyA==", - "dev": true, - "requires": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.7.1.tgz", + "integrity": "sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g==", + "dev": true, + "requires": { + "@azure/identity": "^4.1.0", + "@secretlint/node": "^10.1.2", + "@secretlint/secretlint-formatter-sarif": "^10.1.2", + "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", + "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", + "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.9", - "commander": "^6.2.1", - "glob": "^7.0.6", + "cockatiel": "^3.1.2", + "commander": "^12.1.0", + "form-data": "^4.0.0", + "glob": "^11.0.0", "hosted-git-info": "^4.0.2", "jsonc-parser": "^3.2.0", "keytar": "^7.7.0", "leven": "^3.1.0", - "markdown-it": "^12.3.2", + "markdown-it": "^14.1.0", "mime": "^1.3.4", "minimatch": "^3.0.3", "parse-semver": "^1.1.1", "read": "^1.0.7", + "secretlint": "^10.1.2", "semver": "^7.5.2", - "tmp": "^0.2.1", + "tmp": "^0.2.3", "typed-rest-client": "^1.8.4", "url-join": "^4.0.1", "xml2js": "^0.5.0", @@ -6613,21 +8901,112 @@ }, "dependencies": { "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "dependencies": { + "minimatch": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", + "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==", + "dev": true, + "requires": { + "@isaacs/brace-expansion": "^5.0.0" + } + } } } } }, + "@vscode/vsce-sign": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.9.tgz", + "integrity": "sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g==", + "dev": true, + "requires": { + "@vscode/vsce-sign-alpine-arm64": "2.0.6", + "@vscode/vsce-sign-alpine-x64": "2.0.6", + "@vscode/vsce-sign-darwin-arm64": "2.0.6", + "@vscode/vsce-sign-darwin-x64": "2.0.6", + "@vscode/vsce-sign-linux-arm": "2.0.6", + "@vscode/vsce-sign-linux-arm64": "2.0.6", + "@vscode/vsce-sign-linux-x64": "2.0.6", + "@vscode/vsce-sign-win32-arm64": "2.0.6", + "@vscode/vsce-sign-win32-x64": "2.0.6" + } + }, + "@vscode/vsce-sign-alpine-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", + "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==", + "dev": true, + "optional": true + }, + "@vscode/vsce-sign-alpine-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", + "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==", + "dev": true, + "optional": true + }, + "@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", + "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==", + "dev": true, + "optional": true + }, + "@vscode/vsce-sign-darwin-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", + "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==", + "dev": true, + "optional": true + }, + "@vscode/vsce-sign-linux-arm": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", + "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==", + "dev": true, + "optional": true + }, + "@vscode/vsce-sign-linux-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", + "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==", + "dev": true, + "optional": true + }, + "@vscode/vsce-sign-linux-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", + "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", + "dev": true, + "optional": true + }, + "@vscode/vsce-sign-win32-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", + "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==", + "dev": true, + "optional": true + }, + "@vscode/vsce-sign-win32-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", + "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==", + "dev": true, + "optional": true + }, "@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -6775,23 +9154,25 @@ } }, "@webpack-cli/configtest": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", - "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", "dev": true, "requires": {} }, "@webpack-cli/info": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", - "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", "dev": true, - "requires": {} + "requires": { + "envinfo": "^7.7.3" + } }, "@webpack-cli/serve": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", - "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", "dev": true, "requires": {} }, @@ -6865,6 +9246,15 @@ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true }, + "ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "dev": true, + "requires": { + "environment": "^1.0.0" + } + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -6872,12 +9262,12 @@ "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "anymatch": { @@ -6928,6 +9318,12 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "async-hook-jl": { "version": "1.7.6", "resolved": "https://registry.npmjs.org/async-hook-jl/-/async-hook-jl-1.7.6.tgz", @@ -6958,9 +9354,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "azure-devops-node-api": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.2.0.tgz", - "integrity": "sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==", + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", "dev": true, "requires": { "tunnel": "0.0.6", @@ -6985,6 +9381,15 @@ "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, + "binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "requires": { + "editions": "^6.21.0" + } + }, "bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -7028,10 +9433,16 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, + "boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "dev": true + }, "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -7071,23 +9482,44 @@ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", "dev": true, "requires": { - "es-define-property": "^1.0.0", + "run-applescript": "^7.0.0" + } + }, + "call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "requires": { "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "function-bind": "^1.1.2" + } + }, + "call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "requires": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" } }, "callsites": { @@ -7133,14 +9565,13 @@ } }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, "check-error": { @@ -7268,19 +9699,25 @@ } } }, + "cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "dev": true + }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, "colorette": { @@ -7298,9 +9735,9 @@ } }, "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true }, "concat-map": { @@ -7355,11 +9792,11 @@ "dev": true }, "debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, "decamelize": { @@ -7400,17 +9837,28 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "default-browser": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz", + "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==", "dev": true, "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" } }, + "default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true + }, + "define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -7498,6 +9946,40 @@ "domhandler": "^5.0.3" } }, + "dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "requires": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + } + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "requires": { + "version-range": "^4.15.0" + } + }, "electron-to-chromium": { "version": "1.5.13", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", @@ -7545,25 +10027,26 @@ "dev": true }, "envinfo": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.9.0.tgz", - "integrity": "sha512-RODB4txU+xImYDemN5DqaKC0CHk05XSVkOX4pq0hK26Qx+1LChkuOyUDlGEjYb3ACr0n9qBhFjg37hQuJvpkRQ==", + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true + }, + "environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", "dev": true }, "es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.4" - } + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==" }, "es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, "es-module-lexer": { "version": "1.3.0", @@ -7571,18 +10054,31 @@ "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==", "dev": true }, + "es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "requires": { + "es-errors": "^1.3.0" + } + }, + "es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "requires": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + } + }, "escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, "eslint": { "version": "8.50.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.50.0.tgz", @@ -7628,40 +10124,6 @@ "text-table": "^0.2.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", @@ -7683,21 +10145,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } } } }, @@ -7794,16 +10241,16 @@ "dev": true }, "fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "dependencies": { "glob-parent": { @@ -7829,6 +10276,12 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true + }, "fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -7903,13 +10356,25 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + } + }, "form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" } }, @@ -7961,16 +10426,29 @@ "dev": true }, "get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "requires": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + } + }, + "get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "requires": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" } }, "github-from-package": { @@ -7994,9 +10472,9 @@ }, "dependencies": { "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "requires": { "balanced-match": "^1.0.0" @@ -8052,13 +10530,9 @@ } }, "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==" }, "graceful-fs": { "version": "4.2.11", @@ -8072,32 +10546,24 @@ "dev": true }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "has-property-descriptors": { + "has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==" + }, + "has-tostringtag": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "requires": { - "es-define-property": "^1.0.0" + "has-symbols": "^1.0.3" } }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, "hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", @@ -8217,6 +10683,12 @@ "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, + "index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -8241,9 +10713,9 @@ "optional": true }, "interpret": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", - "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true }, "is-binary-path": { @@ -8263,6 +10735,12 @@ "hasown": "^2.0.2" } }, + "is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true + }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -8284,6 +10762,15 @@ "is-extglob": "^2.1.1" } }, + "is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "requires": { + "is-docker": "^3.0.0" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -8317,6 +10804,15 @@ "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true }, + "is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dev": true, + "requires": { + "is-inside-container": "^1.0.0" + } + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -8335,6 +10831,26 @@ "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true }, + "istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "dev": true, + "requires": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + } + }, + "jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2" + } + }, "jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -8346,12 +10862,6 @@ "supports-color": "^8.0.0" }, "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -8363,10 +10873,16 @@ } } }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", "dev": true, "requires": { "argparse": "^2.0.1" @@ -8390,6 +10906,12 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, "jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", @@ -8404,6 +10926,24 @@ "universalify": "^2.0.0" } }, + "jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "dev": true, + "requires": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + } + }, "jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -8422,6 +10962,27 @@ "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", "dev": true }, + "jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "requires": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "requires": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "keytar": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", @@ -8465,12 +11026,12 @@ } }, "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, "requires": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, "loader-runner": { @@ -8499,12 +11060,60 @@ "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", "dev": true }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -8513,57 +11122,6 @@ "requires": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "loupe": { @@ -8584,30 +11142,28 @@ } }, "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "requires": { "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true - } + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" } }, + "math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" + }, "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "dev": true }, "merge-stream": { @@ -8674,6 +11230,12 @@ "dev": true, "optional": true }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true + }, "mkdirp-classic": { "version": "0.5.3", "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", @@ -8710,9 +11272,9 @@ }, "dependencies": { "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "requires": { "balanced-match": "^1.0.0" @@ -8724,12 +11286,6 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, "minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -8739,12 +11295,6 @@ "brace-expansion": "^2.0.1" } }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -8762,9 +11312,9 @@ "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==" }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "mute-stream": { "version": "0.0.8", @@ -8844,6 +11394,44 @@ "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, + "node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "requires": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + } + }, + "normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "requires": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "dependencies": { + "hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + } + } + }, "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -8860,9 +11448,9 @@ } }, "object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true }, "once": { @@ -8874,6 +11462,18 @@ "wrappy": "1" } }, + "open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "requires": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + } + }, "optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -8906,12 +11506,24 @@ "p-limit": "^3.0.2" } }, + "p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -8927,6 +11539,25 @@ "callsites": "^3.0.0" } }, + "parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "dependencies": { + "type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true + } + } + }, "parse-semver": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", @@ -8986,6 +11617,24 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "path-scurry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", + "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==", + "dev": true, + "requires": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "dependencies": { + "lru-cache": { + "version": "11.2.4", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", + "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true + } + } + }, "path-to-regexp": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.9.0.tgz", @@ -9022,9 +11671,9 @@ "dev": true }, "picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true }, "picomatch": { @@ -9081,6 +11730,12 @@ } } }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true + }, "postinstall-build": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/postinstall-build/-/postinstall-build-5.0.3.tgz", @@ -9137,13 +11792,19 @@ "once": "^1.3.1" } }, + "punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true + }, "qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "version": "6.14.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz", + "integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==", "dev": true, "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.1.0" } }, "queue-microtask": { @@ -9183,6 +11844,18 @@ } } }, + "rc-config-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + } + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -9192,6 +11865,27 @@ "mute-stream": "~0.0.4" } }, + "read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "dependencies": { + "type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true + } + } + }, "readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -9217,12 +11911,12 @@ } }, "rechoir": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", - "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "requires": { - "resolve": "^1.20.0" + "resolve": "^1.9.0" } }, "require-directory": { @@ -9231,6 +11925,12 @@ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require-in-the-middle": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.3.0.tgz", @@ -9305,6 +12005,12 @@ } } }, + "run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true + }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -9342,6 +12048,61 @@ "ajv-keywords": "^3.5.2" } }, + "secretlint": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz", + "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==", + "dev": true, + "requires": { + "@secretlint/config-creator": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/node": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "debug": "^4.4.1", + "globby": "^14.1.0", + "read-pkg": "^9.0.1" + }, + "dependencies": { + "globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "requires": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + } + }, + "ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true + }, + "path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true + }, + "slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true + }, + "unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true + } + } + }, "semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -9359,20 +12120,6 @@ "randombytes": "^2.1.0" } }, - "set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "requires": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - } - }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -9409,16 +12156,59 @@ "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==" }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + } + }, + "side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "requires": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + } + }, + "side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "requires": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + } + }, + "side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" } }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + }, "simple-concat": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", @@ -9450,23 +12240,6 @@ "diff": "^5.1.0", "nise": "^5.1.4", "supports-color": "^7.2.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "slash": { @@ -9475,6 +12248,17 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9491,6 +12275,38 @@ "source-map": "^0.6.0" } }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.22", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", + "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", + "dev": true + }, "stack-chain": { "version": "1.3.7", "resolved": "https://registry.npmjs.org/stack-chain/-/stack-chain-1.3.7.tgz", @@ -9516,6 +12332,17 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -9525,19 +12352,47 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, + "structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "dev": true, + "requires": { + "boundary": "^2.0.0" + } + }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" } }, "supports-preserve-symlinks-flag": { @@ -9545,6 +12400,39 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, + "table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, "tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -9552,9 +12440,9 @@ "dev": true }, "tar-fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz", - "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", "dev": true, "optional": true, "requires": { @@ -9592,6 +12480,16 @@ } } }, + "terminal-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz", + "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==", + "dev": true, + "requires": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^3.2.0" + } + }, "terser": { "version": "5.31.6", "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", @@ -9631,15 +12529,21 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", "dev": true, "requires": { - "rimraf": "^3.0.0" + "editions": "^6.21.0" } }, + "tmp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", + "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", + "dev": true + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -9659,57 +12563,6 @@ "enhanced-resolve": "^5.0.0", "micromatch": "^4.0.0", "semver": "^7.3.4" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } } }, "ts-mockito": { @@ -9781,9 +12634,9 @@ "dev": true }, "typed-rest-client": { - "version": "1.8.9", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.9.tgz", - "integrity": "sha512-uSmjE38B80wjL85UFX3sTYEUlvZ1JgCRhsWj/fJ4rZ0FqDUFoIuodtiVeE+cUqiVTOKPdKrp/sdftD15MDek6g==", + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", "dev": true, "requires": { "qs": "^6.9.1", @@ -9809,15 +12662,27 @@ "dev": true }, "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "dev": true }, "underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==", + "version": "1.13.7", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", + "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "dev": true + }, + "undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true + }, + "unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", "dev": true }, "universalify": { @@ -9869,6 +12734,22 @@ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true + }, "vscode-jsonrpc": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz", @@ -9885,9 +12766,9 @@ }, "dependencies": { "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "requires": { "balanced-match": "^1.0.0" } @@ -9958,30 +12839,29 @@ } }, "webpack-cli": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", - "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.1.1", - "@webpack-cli/info": "^2.0.2", - "@webpack-cli/serve": "^2.0.5", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", "colorette": "^2.0.14", - "commander": "^10.0.1", + "commander": "^7.0.0", "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", - "interpret": "^3.1.1", - "rechoir": "^0.8.0", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", "webpack-merge": "^5.7.3" }, "dependencies": { "commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true } } @@ -10032,32 +12912,17 @@ "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "wrappy": { @@ -10066,6 +12931,15 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "requires": { + "is-wsl": "^3.1.0" + } + }, "xml2js": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", diff --git a/package.json b/package.json index 61c8c7a8..ec47d048 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "debugpy", "displayName": "Python Debugger", "description": "Python Debugger extension using debugpy.", - "version": "2025.9.0-dev", + "version": "2025.19.0-dev", "publisher": "ms-python", "enabledApiProposals": [ "portsAttributes", @@ -139,6 +139,27 @@ "tags": [ "experimental" ] + }, + "debugpy.onErrors": { + "default": "debugAnyway", + "description": "%debugpy.onErrors.description%", + "scope": "resource", + "type": "string", + "enum": [ + "debugAnyway", + "showErrors", + "abort", + "prompt" + ], + "enumDescriptions": [ + "Continue debugging.", + "Show errors and stop debugging.", + "Stop debugging.", + "Let the user choose the action." + ], + "tags": [ + "experimental" + ] } }, "title": "Python Debugger", @@ -256,6 +277,24 @@ "description": "Enable logging of debugger events to a log file. This file can be found in the debugpy extension install folder.", "type": "boolean" }, + "terminalQuoteCharacter": { + "default": null, + "description": "The quoting character to be used by the debugger when quoting terminal commands.", + "type": [ + "string", + "null" + ], + "enum": [ + "\"", + "'", + "`" + ], + "enumDescriptions": [ + "Double quote (\")", + "Single quote (')", + "Backtick (`)" + ] + }, "pathMappings": { "default": [], "items": { @@ -452,6 +491,24 @@ "description": "Enable logging of debugger events to a log file. This file can be found in the debugpy extension install folder.", "type": "boolean" }, + "terminalQuoteCharacter": { + "default": null, + "description": "The quoting character to be used by the debugger when quoting terminal commands.", + "type": [ + "string", + "null" + ], + "enum": [ + "\"", + "'", + "`" + ], + "enumDescriptions": [ + "Double quote (\")", + "Single quote (')", + "Backtick (`)" + ] + }, "module": { "default": "", "description": "Name of the module to be debugged.", @@ -606,26 +663,26 @@ "watch-tests": "tsc -p . -w --outDir out", "pretest": "npm run compile-tests && npm run compile && npm run lint", "lint": "eslint src --ext ts", - "format-check": "prettier --check 'src/**/*.ts' 'build/**/*.yml' '.github/**/*.yml'", - "format-fix": "prettier --write 'src/**/*.ts' 'build/**/*.yml' '.github/**/*.yml'", + "format-check": "prettier --check \"src/**/*.ts\" \"build/**/*.yml\" \".github/**/*.yml\"", + "format-fix": "prettier --write \"src/**/*.ts\" \"build/**/*.yml\" \".github/**/*.yml\"", "test": "node ./out/test/runTest.js", "vsce-package": "npx @vscode/vsce package -o python-debugger.vsix" }, "devDependencies": { - "@types/chai": "^4.3.4", - "@types/chai-as-promised": "^7.1.8", + "@types/chai": "^4.1.2", + "@types/chai-as-promised": "^7.1.0", "@types/fs-extra": "^11.0.4", "@types/glob": "^7.2.0", - "@types/lodash": "^4.14.191", - "@types/mocha": "^10.0.7", - "@types/node": "18.x", - "@types/semver": "^7.3.13", + "@types/lodash": "^4.14.104", + "@types/mocha": "^9.1.0", + "@types/node": "^22.5.0", + "@types/semver": "^5.5.0", "@types/sinon": "^10.0.13", "@types/vscode": "^1.87.0", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "@vscode/test-electron": "^2.3.9", - "@vscode/vsce": "^2.24.0", + "@vscode/vsce": "^3.7.1-1", "chai": "^4.3.7", "chai-as-promised": "^7.1.1", "eslint": "^8.50.0", @@ -638,17 +695,17 @@ "ts-mockito": "^2.6.1", "typemoq": "^2.1.0", "typescript": "^5.5.4", - "webpack": "^5.87.0", - "webpack-cli": "^5.1.4" + "webpack": "^5.76.0", + "webpack-cli": "^4.9.2" }, "dependencies": { "@vscode/debugadapter": "^1.65.0", "@vscode/debugprotocol": "^1.65.0", - "@vscode/extension-telemetry": "^0.8.5", - "@vscode/python-extension": "^1.0.5", + "@vscode/extension-telemetry": "^0.8.4", + "@vscode/python-extension": "^1.0.6", "fs-extra": "^11.2.0", "iconv-lite": "^0.6.3", - "jsonc-parser": "^3.2.0", + "jsonc-parser": "^3.0.0", "lodash": "^4.17.21", "vscode-languageclient": "^8.0.2" } diff --git a/package.nls.json b/package.nls.json index 5a53eb61..0db72986 100644 --- a/package.nls.json +++ b/package.nls.json @@ -5,5 +5,6 @@ "debugpy.command.reportIssue.title": "Report Issue...", "debugpy.command.viewOutput.title": "Show Output", "debugpy.debugJustMyCode.description": "When debugging only step through user-written code. Disable this to allow stepping into library code.", - "debugpy.showPythonInlineValues.description": "Whether to display inline values in the editor while debugging." + "debugpy.showPythonInlineValues.description": "Whether to display inline values in the editor while debugging.", + "debugpy.onErrors.description": "Controls what to do when errors are encountered before debugging." } diff --git a/packages.config b/packages.config new file mode 100644 index 00000000..6055d985 --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/pre-built/l10n/bundle.l10n.cs.json b/pre-built/l10n/bundle.l10n.cs.json new file mode 100644 index 00000000..1d912032 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.cs.json @@ -0,0 +1 @@ +{"Attach to a local process":"Připojit k místnímu procesu","Attach to a remote debug server":"Připojit ke vzdálenému ladicímu serveru","Attach to process":"Připojit k procesu","Attach using Process ID":"Připojit přes ID procesu","Browse Files...":"Procházet soubory...","Browse your file system to find a Python file.":"Vyhledejte soubor Pythonu procházením systému souborů.","Change Python Interpreter":"Změnit interpret Pythonu","Command Line Arguments":"Argumenty příkazového řádku","Debug Configuration":"Ladit konfiguraci","Debug Django":"Ladění Django","Debug FastAPI":"Ladit FastAPI","Debug Flask":"Ladit Flask","Debug Module":"Ladící modul","Debug Pyramid":"Ladit Pyramid","Debug Stopped":"Ladění zastaveno","Debug a Python module by invoking it with '-m'":"Ladit modul Python jeho vyvoláním přes '-m'","Debug the currently active Python file":"Ladit aktuálně aktivní soubor Python","Debug the currently active Python file with arguments":"Ladění aktuálně aktivního souboru Pythonu s argumenty","Django":"Django","Do not show again":"Už nezobrazovat","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Povolí použití [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, na terminálu.","Enter a Python module/package name":"Zadejte název modulu/balíčku Python","Enter a valid file path":"Zadejte platnou cestu k souboru","Enter a valid host name or IP address":"Zadejte platný název hostitele nebo IP adresu.","Enter a valid module name":"Zadejte platný název modulu","Enter a valid name":"Vložte platné jméno.","Enter a valid port number":"Zadejte platné číslo portu","Enter the command line arguments you want to pass to the program":"Zadejte argumenty příkazového řádku, které chcete programu předat.","Enter the path to app.py or select a file from the list.":"Zadejte cestu k app.py nebo vyberte soubor ze seznamu.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Zadejte cestu k development.ini ({0} odkazuje na kořen aktuální složky pracovního prostoru).","Enter the path to manage.py or select a file from the list.":"Zadejte cestu k manage.py nebo vyberte soubor ze seznamu.","Enter the path to the application, e.g. 'main.py' or 'main'":"Zadejte cestu k aplikaci, např. main.py nebo main","Enter the port number that the debug server is listening on":"Zadejte číslo portu, ve kterém naslouchá ladící server","Failed to launch debugger for child process {0}":"Spouštění ladicího programu pro podřízený proces {0} se nezdařilo","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Spustit a ladit webovou aplikaci Django","Launch and debug a FastAPI web application":"Spustit a ladit webovou aplikaci FastAPI","Launch and debug a Flask web application":"Spustit a ladit webovou aplikaci Flask","Launch and debug a Pyramid web application":"Spustit a ladit webovou aplikaci Pyramid","Module":"Modul","More Info":"Další informace","No process selected":"Nevybral se žádný proces.","No, I will do it later":"Ano, chci upozornit","Open launch.json":"Otevřít soubor launch.json","Operating system '{0}' not supported.":"Operační systém {0} se nepodporuje.","Pyramid":"Pyramida","Python Debugger":"Ladicí program Pythonu","Python Debugger extension loading...":"Načítá se rozšíření Ladicího programu Python...","Python Debugger: Attach using Process Id":"Ladicí program Pythonu: Připojit přes ID procesu","Python Debugger: Current File":"Ladicí program Pythonu: Aktuální soubor","Python Debugger: Current File with Arguments":"Ladicí program Pythonu: Aktuální soubor s argumenty","Python Debugger: Django":"Ladicí program Pythonu: Django","Python Debugger: FastAPI":"Ladicí program Pythonu: FastAPI","Python Debugger: Flask":"Ladicí program Pythonu: Flask","Python Debugger: Module":"Ladicí program Pythonu: Modul","Python Debugger: Pyramid Application":"Ladicí program Pythonu: Aplikace Pyramid","Python Debugger: Remote Attach":"Ladicí program Pythonu: Vzdálené připojení","Python File":"Soubor Python","Python File with Arguments":"Soubor Pythonu s argumenty","Refresh process list":"Aktualizovat seznam procesů","Remote Attach":"Vzdálené připojení","Remote Debugging":"Vzdálené ladění","Select File":"Vybrat soubor","Select Python File":"Vybrat soubor Pythonu","Select Python Interpreter":"Vybrat interpret Pythonu","Select a Python Debugger debug configuration":"Vyberte konfiguraci ladění pro ladicí program Pythonu","Select a debug configuration":"Vyberte konfiguraci ladění","Select the process to attach to":"Vyberte proces, ke kterému se má program připojit.","Show as Hex":"Zobrazit jako šestnáctkovou hodnotu","The minimum supported Python version for the debugger extension is 3.9.":"Minimální podporovaná verze Pythonu pro rozšíření ladicího programu je 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Všimli jsme si, že se připojujete k ptvsd (ladicí program Python), který je od 1. května 2020 zastaralý. Přejděte prosím na [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Než spustíte ladění, musíte vybrat interpret Pythonu.\n\nTip: Klikněte na „Vybrat interpret“ ve stavovém řádku.","cwd:":"cwd:","enter-your-module-name":"zadejte-svůj-název-modulu"} diff --git a/pre-built/l10n/bundle.l10n.de.json b/pre-built/l10n/bundle.l10n.de.json new file mode 100644 index 00000000..ed0fd8b6 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.de.json @@ -0,0 +1 @@ +{"Attach to a local process":"An einen lokalen Prozess anhängen","Attach to a remote debug server":"An einen Remote-Debug-Server anhängen","Attach to process":"An Prozess anhängen","Attach using Process ID":"Mit Prozess-ID anhängen","Browse Files...":"Dateien durchsuchen...","Browse your file system to find a Python file.":"Durchsuchen Sie Ihr Dateisystem nach einer Python-Datei.","Change Python Interpreter":"Python-Interpreter ändern","Command Line Arguments":"Befehlszeilenargumente","Debug Configuration":"Konfiguration debuggen","Debug Django":"Django debuggen","Debug FastAPI":"FastAPI debuggen","Debug Flask":"Flask debuggen","Debug Module":"Debuggen-Modul","Debug Pyramid":"Pyramide debuggen","Debug Stopped":"Debuggen beendet","Debug a Python module by invoking it with '-m'":"Debuggen Sie ein Python-Modul, indem Sie es mit „-m“ aufrufen.","Debug the currently active Python file":"Debuggen Sie die derzeit aktive Python-Datei","Debug the currently active Python file with arguments":"Debuggen Sie die derzeit aktive Python-Datei mit Argumenten.","Django":"Django","Do not show again":"Nicht mehr anzeigen","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Aktiviert die Verwendung von [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), \"debugpy \" im Terminal.","Enter a Python module/package name":"Geben Sie einen Python-Modul-/Paketnamen ein","Enter a valid file path":"Geben Sie einen gültigen Dateipfad ein","Enter a valid host name or IP address":"Geben Sie einen gültigen Hostnamen oder eine gültige IP-Adresse ein.","Enter a valid module name":"Geben Sie einen gültigen Modulnamen ein","Enter a valid name":"Geben Sie einen gültigen Namen ein","Enter a valid port number":"Geben Sie eine gültige Portnummer ein","Enter the command line arguments you want to pass to the program":"Geben Sie die Befehlszeilenargumente ein, die an das Programm übergeben werden.","Enter the path to app.py or select a file from the list.":"Geben Sie den Pfad zum app.py ein, oder wählen Sie eine Datei aus der Liste aus.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Geben Sie den Pfad zu development.ini ein ({0} zeigt auf das Stammverzeichnis des aktuellen Arbeitsbereichsordners)","Enter the path to manage.py or select a file from the list.":"Geben Sie den Pfad zum manage.py ein, oder wählen Sie eine Datei aus der Liste aus.","Enter the path to the application, e.g. 'main.py' or 'main'":"Geben Sie den Pfad zur Anwendung ein, z. 'main.py' oder 'main'","Enter the port number that the debug server is listening on":"Geben Sie die Portnummer ein, die der Debug-Server überwacht","Failed to launch debugger for child process {0}":"Fehler beim Starten des Debuggers für den untergeordneten Prozess {0}","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Starten und debuggen Sie eine Django-Webanwendung","Launch and debug a FastAPI web application":"Starten und debuggen Sie eine FastAPI-Webanwendung","Launch and debug a Flask web application":"Starten und debuggen Sie eine Flask-Webanwendung","Launch and debug a Pyramid web application":"Starten und debuggen Sie eine Pyramid-Webanwendung","Module":"Modul","More Info":"Weitere Info","No process selected":"Kein Prozess ausgewählt","No, I will do it later":"Nein, mache ich später","Open launch.json":"launch.json öffnen","Operating system '{0}' not supported.":"Betriebssystem '{0}' wird nicht unterstützt.","Pyramid":"Pyramide","Python Debugger":"Python-Debugger","Python Debugger extension loading...":"Python-Debuggererweiterung wird geladen...","Python Debugger: Attach using Process Id":"Python-Debugger: Über Prozess-ID anfügen","Python Debugger: Current File":"Python-Debugger: Aktuelle Datei","Python Debugger: Current File with Arguments":"Python-Debugger: Aktuelle Datei mit Argumenten","Python Debugger: Django":"Python-Debugger: Django","Python Debugger: FastAPI":"Python-Debugger: FastAPI","Python Debugger: Flask":"Python-Debugger: Flask","Python Debugger: Module":"Python-Debugger: Modul","Python Debugger: Pyramid Application":"Python-Debugger: Pyramid-Anwendung","Python Debugger: Remote Attach":"Python-Debugger: Remoteanfügung","Python File":"Python-Datei","Python File with Arguments":"Python-Datei mit Argumenten","Refresh process list":"Prozessliste aktualisieren","Remote Attach":"Remoteanfügung","Remote Debugging":"Remotedebuggen","Select File":"Datei auswählen","Select Python File":"Python-Datei auswählen","Select Python Interpreter":"Python-Interpreter auswählen","Select a Python Debugger debug configuration":"Debugkonfiguration für Python-Debugger auswählen","Select a debug configuration":"Debugkonfiguration auswählen","Select the process to attach to":"Prozess auswählen, an den angefügt werden soll","Show as Hex":"Als Hex anzeigen","The minimum supported Python version for the debugger extension is 3.9.":"Die minimale unterstützte Python-Version für die Debuggererweiterung ist 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Wir haben festgestellt, dass Sie ptvsd (Python-Debugger) anhängen, das am 1. Mai 2020 veraltet ist. Bitte wechseln Sie zu [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Sie müssen einen Python-Interpreter auswählen, bevor Sie mit dem Debuggen beginnen.\n\nTipp: Klicken Sie in der Statusleiste auf „Interpreter auswählen“.","cwd:":"сwd:","enter-your-module-name":"Geben Sie Ihren Modulnamen ein"} diff --git a/pre-built/l10n/bundle.l10n.es.json b/pre-built/l10n/bundle.l10n.es.json new file mode 100644 index 00000000..90592111 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.es.json @@ -0,0 +1 @@ +{"Attach to a local process":"Asociar a un proceso emulador local","Attach to a remote debug server":"Asociar a un servidor de depuración remoto","Attach to process":"Asociar al proceso","Attach using Process ID":"Adjuntar mediante un id. de proceso","Browse Files...":"Examinar archivos...","Browse your file system to find a Python file.":"Examine el sistema de archivos para buscar un archivo de Python.","Change Python Interpreter":"Cambiar intérprete de Python","Command Line Arguments":"Argumentos de la línea de comandos","Debug Configuration":"Configuración de depuración","Debug Django":"Depurar Django","Debug FastAPI":"Depurar FastAPI","Debug Flask":"Depurar Flask","Debug Module":"Módulo de depuración","Debug Pyramid":"Depurar Pyramid","Debug Stopped":"Depuración detenida","Debug a Python module by invoking it with '-m'":"Depuración de un módulo de Python invocándolo con \\\"-m\\\"","Debug the currently active Python file":"Depurar el archivo de Python activo actualmente","Debug the currently active Python file with arguments":"Depurar el archivo de Python activo actualmente con argumentos","Django":"Django","Do not show again":"No volver a mostrar","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Habilita el uso de [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), 'debugpy ', en el terminal.","Enter a Python module/package name":"Escriba un nombre de módulo o paquete de Python","Enter a valid file path":"Escriba una ruta de acceso de archivo válida","Enter a valid host name or IP address":"Escribir un nombre o dirección IP de host válidos","Enter a valid module name":"Escriba un nombre de módulo válido","Enter a valid name":"Especifique un nombre válido","Enter a valid port number":"Escriba un número de puerto válido.","Enter the command line arguments you want to pass to the program":"Escriba los argumentos de la línea de comandos que desea pasar al programa","Enter the path to app.py or select a file from the list.":"Escriba la ruta de acceso a app.py o seleccione un archivo de la lista.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Escriba la ruta de acceso a development.ini ({0} apunta a la raíz de la carpeta del área de trabajo actual)","Enter the path to manage.py or select a file from the list.":"Escriba la ruta de acceso a manage.py o seleccione un archivo de la lista.","Enter the path to the application, e.g. 'main.py' or 'main'":"Escriba la ruta de acceso a la aplicación; por ejemplo, \\\"main.py\\\" o \\\"main\\\".","Enter the port number that the debug server is listening on":"Escriba el número de puerto en el que escucha el servidor de depuración.","Failed to launch debugger for child process {0}":"No se pudo iniciar el depurador para el {0} de procesos secundarios","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Inicio y depuración de una aplicación web Django","Launch and debug a FastAPI web application":"Iniciar y depurar una aplicación web FastAPI","Launch and debug a Flask web application":"Inicio y depuración de una aplicación web de Flask","Launch and debug a Pyramid web application":"Inicio y depuración de una aplicación web Pyramid","Module":"Módulo","More Info":"Más información","No process selected":"No se ha seleccionado ningún proceso","No, I will do it later":"No, lo haré más tarde","Open launch.json":"Abrir launch.json","Operating system '{0}' not supported.":"No se admite el sistema operativo \\\"{0}\\\".","Pyramid":"Pyramid","Python Debugger":"Depurador de Python","Python Debugger extension loading...":"Cargando la extensión del depurador de Python...","Python Debugger: Attach using Process Id":"Depurador de Python: Adjuntar mediante un id. de proceso","Python Debugger: Current File":"Depurador de Python: Archivo actual","Python Debugger: Current File with Arguments":"Depurador de Python: Archivo actual con argumentos","Python Debugger: Django":"Depurador de Python: Django","Python Debugger: FastAPI":"Depurador de Python: FastAPI","Python Debugger: Flask":"Depurador de Python: Flask","Python Debugger: Module":"Depurador de Python: Módulo","Python Debugger: Pyramid Application":"Depurador de Python: Aplicación Pyramid","Python Debugger: Remote Attach":"Depurador de Python: Conexión remota","Python File":"Archivo de Python","Python File with Arguments":"Archivo de Python con argumentos","Refresh process list":"Actualizar la lista de procesos","Remote Attach":"Conexión remota","Remote Debugging":"Depuración remota","Select File":"Seleccionar archivo","Select Python File":"Seleccionar archivo de Python","Select Python Interpreter":"Seleccionar un intérprete de Python","Select a Python Debugger debug configuration":"Seleccionar una configuración de depuración del depurador de Python","Select a debug configuration":"Seleccione una configuración de depuración","Select the process to attach to":"Seleccione el proceso al que debe asociarse","Show as Hex":"Mostrar como hexadecimal","The minimum supported Python version for the debugger extension is 3.9.":"La versión mínima admitida de Python para la extensión del depurador es la 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Hemos observado que está adjuntando a ptvsd (depurador de Python), que quedó en desuso el 1 de mayo de 2020. Cambie a [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Debe seleccionar un intérprete de Python antes de iniciar la depuración.\n\nSugerencia: haga clic en \"Seleccionar intérprete\" en la barra de estado.","cwd:":"cwd:","enter-your-module-name":"escriba-el-nombre-de-su-módulo"} diff --git a/pre-built/l10n/bundle.l10n.fr.json b/pre-built/l10n/bundle.l10n.fr.json new file mode 100644 index 00000000..e89fbea8 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.fr.json @@ -0,0 +1 @@ +{"Attach to a local process":"Attacher à un processus local","Attach to a remote debug server":"Attacher à un serveur de débogage distant","Attach to process":"Attacher au processus","Attach using Process ID":"Attacher à l’aide de l’ID de processus","Browse Files...":"Parcourir les fichiers...","Browse your file system to find a Python file.":"Parcourez votre système de fichiers pour trouver un fichier Python.","Change Python Interpreter":"Modifier l’interpréteur Python","Command Line Arguments":"Arguments de la ligne de commande","Debug Configuration":"Configuration du débogage","Debug Django":"Déboguer l'application Django","Debug FastAPI":"Déboguer FastAPI","Debug Flask":"Déboguer Flask","Debug Module":"Déboguer le module","Debug Pyramid":"Déboguer Pyramid","Debug Stopped":"Débogage arrêté","Debug a Python module by invoking it with '-m'":"Déboguer un module Python en l’appelant avec '-m'","Debug the currently active Python file":"Déboguer le fichier Python actuellement actif","Debug the currently active Python file with arguments":"Déboguer le fichier Python actuellement actif avec des arguments","Django":"Django","Do not show again":"Ne plus afficher","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Permet d’activer l’utilisation du [débogage sans configuration](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, dans le terminal.","Enter a Python module/package name":"Entrer un nom de module/package Python","Enter a valid file path":"Entrez un chemin de fichier valide","Enter a valid host name or IP address":"Entrer un nom d’hôte ou une adresse IP valide","Enter a valid module name":"Entrez un nom de module valide","Enter a valid name":"Entrez un nom valide.","Enter a valid port number":"Entrez un numéro de port valide.","Enter the command line arguments you want to pass to the program":"Entrez les arguments de ligne de commande que vous souhaitez transmettre au programme","Enter the path to app.py or select a file from the list.":"Entrez le chemin d’accès à app.py ou sélectionnez un fichier dans la liste.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Entrez le chemin d’accès au fichier development.ini ({0} pointe vers la racine du dossier d’espace de travail actuel)","Enter the path to manage.py or select a file from the list.":"Entrez le chemin d’accès à manage.py ou sélectionnez un fichier dans la liste.","Enter the path to the application, e.g. 'main.py' or 'main'":"Entrez le chemin d’accès à l’application, par ex., « main.py » ou « main »","Enter the port number that the debug server is listening on":"Entrez le numéro de port sur lequel le serveur de débogage écoute","Failed to launch debugger for child process {0}":"Échec du lancement du débogueur pour le processus enfant {0}","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Lancer et déboguer une application web Django","Launch and debug a FastAPI web application":"Lancer et déboguer une application web FastAPI","Launch and debug a Flask web application":"Lancer et déboguer une application web Flask","Launch and debug a Pyramid web application":"Lancer et déboguer une application web Pyramid","Module":"Module","More Info":"Informations supplémentaires","No process selected":"Aucun processus sélectionné","No, I will do it later":"Non, je le fais plus tard","Open launch.json":"Ouvrir launch.json","Operating system '{0}' not supported.":"Le système d’exploitation «{0}» n’est pas pris en charge.","Pyramid":"Pyramide","Python Debugger":"Débogueur Python","Python Debugger extension loading...":"Chargement de l’extension du débogueur Python...","Python Debugger: Attach using Process Id":"Débogueur Python : Joindre à l'aide de l'ID de processus","Python Debugger: Current File":"Débogueur Python : Fichier actuel","Python Debugger: Current File with Arguments":"Débogueur Python : Fichier actuel avec arguments","Python Debugger: Django":"Débogueur Python : Django","Python Debugger: FastAPI":"Débogueur Python : FastAPI","Python Debugger: Flask":"Débogueur Python : Flask","Python Debugger: Module":"Débogueur Python : Module","Python Debugger: Pyramid Application":"Débogueur Python : Application Pyramide","Python Debugger: Remote Attach":"Débogueur Python : Attachement à distance","Python File":"Fichier Python","Python File with Arguments":"Fichier Python avec arguments","Refresh process list":"Actualiser la liste des processus","Remote Attach":"Attachement distant","Remote Debugging":"Débogage distant","Select File":"Sélectionner un fichier","Select Python File":"Sélectionner un fichier Python","Select Python Interpreter":"Sélectionner l’interpréteur Python","Select a Python Debugger debug configuration":"Sélectionnez une configuration de débogage du débogueur Python","Select a debug configuration":"Sélectionnez une configuration de débogage","Select the process to attach to":"Sélectionner le processus à attacher","Show as Hex":"Afficher en tant que hexadécimal","The minimum supported Python version for the debugger extension is 3.9.":"La version minimale prise en charge par Python pour l’extension du débogueur est la 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Nous avons remarqué que vous vous attachiez à ptvsd (débogueur Python), qui a été déprécié le 1er mai 2020. Basculez vers [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Vous devez sélectionner un interpréteur Python avant de commencer le débogage. \n\nConseil : cliquez sur « Sélectionner un Interpréteur » dans la barre d’état.","cwd:":"cwd :","enter-your-module-name":"enter-your-module-name"} diff --git a/pre-built/l10n/bundle.l10n.it.json b/pre-built/l10n/bundle.l10n.it.json new file mode 100644 index 00000000..01d9e925 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.it.json @@ -0,0 +1 @@ +{"Attach to a local process":"Consente il collegamento a un processo locale","Attach to a remote debug server":"Consente il collegamento a un server di debug remoto","Attach to process":"Collega a processo","Attach using Process ID":"Collegare tramite ID processo","Browse Files...":"Sfoglia file...","Browse your file system to find a Python file.":"Esplora il file system per individuare un file Python.","Change Python Interpreter":"Modifica interprete Python","Command Line Arguments":"Argomenti della riga di comando","Debug Configuration":"Configurazione di debug","Debug Django":"Eseguire il debug di Django","Debug FastAPI":"Eseguire il debug di FastAPI","Debug Flask":"Esegui il debug di Flask","Debug Module":"Modulo di debug","Debug Pyramid":"Esegui il debug di Pyramid","Debug Stopped":"Debug interrotto","Debug a Python module by invoking it with '-m'":"Eseguire il debug di un modulo Python richiamandolo con '-m'","Debug the currently active Python file":"Eseguire il debug del file Python attivo al momento","Debug the currently active Python file with arguments":"Esegui il debug del file Python attualmente attivo con argomenti","Django":"Django","Do not show again":"Non visualizzare più","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Abilita l'uso di [debug senza configurazione](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), 'debugpy ' nel terminale.","Enter a Python module/package name":"Immettere un nome del modulo/pacchetto Python","Enter a valid file path":"Immettere un percorso di file valido","Enter a valid host name or IP address":"Immettere un nome host o un indirizzo IP valido","Enter a valid module name":"Immettere un nome del modulo valido","Enter a valid name":"Immettere un nome valido.","Enter a valid port number":"Immettere un numero di porta valido","Enter the command line arguments you want to pass to the program":"Immettere gli argomenti della riga di comando da passare al programma","Enter the path to app.py or select a file from the list.":"Immettere il percorso ad app.py o selezionare un file dall'elenco.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"`Immettere il percorso di development.ini ({0} punta alla radice della cartella dell'area di lavoro corrente)","Enter the path to manage.py or select a file from the list.":"Immettere il percorso a manage.py o selezionare un file dall'elenco.","Enter the path to the application, e.g. 'main.py' or 'main'":"Immettere il percorso dell'applicazione, ad esempio 'main.py' o 'main'","Enter the port number that the debug server is listening on":"Immettere il numero di porta di cui il server di debug è in ascolto","Failed to launch debugger for child process {0}":"Non è stato possibile avviare il debugger per il processo figlio {0}","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Avviare ed eseguire il debug di un'applicazione Web Django","Launch and debug a FastAPI web application":"Avviare ed eseguire il debug di un'applicazione Web FastAPI","Launch and debug a Flask web application":"Avviare ed eseguire il debug di un'applicazione Web Flask","Launch and debug a Pyramid web application":"Avviare ed eseguire il debug di un'applicazione Web Pyramid","Module":"Modulo","More Info":"Altre informazioni","No process selected":"Non è stato selezionato alcun processo","No, I will do it later":"No, lo farò in seguito","Open launch.json":"Apri launch.json","Operating system '{0}' not supported.":"Il sistema operativo '{0}' non è supportato.","Pyramid":"Pyramid","Python Debugger":"Debugger Python","Python Debugger extension loading...":"Caricamento dell'estensione del debugger Python in corso...","Python Debugger: Attach using Process Id":"Debugger Python: Collegare tramite ID processo","Python Debugger: Current File":"Debugger Python: File corrente","Python Debugger: Current File with Arguments":"Debugger Python: File corrente con argomenti","Python Debugger: Django":"Debugger Python: Django","Python Debugger: FastAPI":"Debugger Python: FastAPI","Python Debugger: Flask":"Debugger Python: Flask","Python Debugger: Module":"Debugger Python: Modulo","Python Debugger: Pyramid Application":"Debugger Python: Applicazione Pyramid","Python Debugger: Remote Attach":"Debugger Python: Collegamento remoto","Python File":"File Python","Python File with Arguments":"File Python con argomenti","Refresh process list":"Aggiornare l'elenco dei processi","Remote Attach":"Collegamento remoto","Remote Debugging":"Debug remoto","Select File":"Seleziona file","Select Python File":"Seleziona file Python","Select Python Interpreter":"È possibile selezionare l'interprete Python","Select a Python Debugger debug configuration":"Selezionare una configurazione di debug per il debugger Python","Select a debug configuration":"Selezionare una configurazione di debug","Select the process to attach to":"Selezionare il processo a cui collegarsi","Show as Hex":"Mostra come valore esadecimale","The minimum supported Python version for the debugger extension is 3.9.":"La versione minima supportata di Python per l'estensione del debugger è la 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Abbiamo rilevato che si sta tentando il collegamento a ptvsd (debugger Python) che è stato deprecato il 1° maggio 2020. È consigliabile passare a [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"È necessario selezionare un interprete Python prima di avviare il debug.\n\nSuggerimento: fai clic su \"Seleziona interprete Python\" nella barra di stato.","cwd:":"cwd:","enter-your-module-name":"enter-your-module-name"} diff --git a/pre-built/l10n/bundle.l10n.ja.json b/pre-built/l10n/bundle.l10n.ja.json new file mode 100644 index 00000000..1c57c5e2 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.ja.json @@ -0,0 +1 @@ +{"Attach to a local process":"ローカル プロセスに接続する","Attach to a remote debug server":"リモート デバッグ サーバーに接続する","Attach to process":"プロセスに接続","Attach using Process ID":"プロセス ID を使用して接続する","Browse Files...":"ファイルの参照...","Browse your file system to find a Python file.":"ファイル システムを参照して Python ファイルを検索します。","Change Python Interpreter":"Python インタープリターの変更","Command Line Arguments":"コマンド ライン引数","Debug Configuration":"デバッグ構成","Debug Django":"Django をデバッグする","Debug FastAPI":"FastAPI をデバッグする","Debug Flask":"Flask をデバッグする","Debug Module":"モジュールをデバッグする","Debug Pyramid":"ピラミッドをデバッグ","Debug Stopped":"デバッグが停止しました","Debug a Python module by invoking it with '-m'":"Python モジュールを '-m' で呼び出してデバッグする","Debug the currently active Python file":"現在アクティブな Python ファイルをデバッグする","Debug the currently active Python file with arguments":"現在アクティブな引数を含む Python ファイルをデバッグします","Django":"Django","Do not show again":"今後表示しない","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"ターミナルで [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), 'debugpy ' の使用を有効にします。","Enter a Python module/package name":"Python モジュール/パッケージ名を入力する","Enter a valid file path":"有効なファイル パスを入力する","Enter a valid host name or IP address":"有効なホスト名または IP アドレスを入力する","Enter a valid module name":"有効なモジュール名を入力する","Enter a valid name":"有効な名前を入力してください。","Enter a valid port number":"有効なポート番号を入力してください。","Enter the command line arguments you want to pass to the program":"プログラムに渡すコマンド ライン引数を入力します","Enter the path to app.py or select a file from the list.":"app.py へのパスを入力するか、一覧からファイルを選択します。","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"development.ini へのパスを入力します ({0} は現在のワークスペース フォルダーのルートを指しています)","Enter the path to manage.py or select a file from the list.":"manage.py へのパスを入力するか、一覧からファイルを選択します。","Enter the path to the application, e.g. 'main.py' or 'main'":"アプリケーションへのパスを入力する (例: 'main.py'、'main')","Enter the port number that the debug server is listening on":"デバッグ サーバーがリッスンしているポート番号を入力する","Failed to launch debugger for child process {0}":"子プロセス {0} のデバッガーを起動できませんでした","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Django Web アプリケーションの起動とデバッグ","Launch and debug a FastAPI web application":"FastAPI Web アプリケーションの起動とデバッグ","Launch and debug a Flask web application":"Flask Web アプリケーションの起動とデバッグ","Launch and debug a Pyramid web application":"Pyramid Web アプリケーションの起動とデバッグ","Module":"モジュール","More Info":"詳細情報","No process selected":"プロセスが選択されていません","No, I will do it later":"いいえ。後で行います。","Open launch.json":"launch.json を開く","Operating system '{0}' not supported.":"オペレーティング システム '{0}' はサポートされていません。","Pyramid":"ピラミッド","Python Debugger":"Python デバッガー","Python Debugger extension loading...":"Python デバッガー拡張機能の読み込み中...","Python Debugger: Attach using Process Id":"Python デバッガー: プロセス ID を使用してアタッチする","Python Debugger: Current File":"Python デバッガー: 現在のファイル","Python Debugger: Current File with Arguments":"Python デバッガー: 引数を含む現在のファイル","Python Debugger: Django":"Python デバッガー: Django","Python Debugger: FastAPI":"Python デバッガー: FastAPI","Python Debugger: Flask":"Python デバッガー: Flask","Python Debugger: Module":"Python デバッガー: モジュール","Python Debugger: Pyramid Application":"Python デバッガー: ピラミッド アプリケーション","Python Debugger: Remote Attach":"Python デバッガー: リモートアタッチ","Python File":"Python ファイル","Python File with Arguments":"引数を含む Python ファイル","Refresh process list":"プロセスの一覧の更新","Remote Attach":"リモート接続","Remote Debugging":"リモート デバッグ","Select File":"ファイルの選択","Select Python File":"Python ファイルの選択","Select Python Interpreter":"Python インタープリターの選択","Select a Python Debugger debug configuration":"Python デバッグ構成を選択する","Select a debug configuration":"デバッグ構成を選択する","Select the process to attach to":"アタッチするプロセスを選択する","Show as Hex":"16 進数で表示","The minimum supported Python version for the debugger extension is 3.9.":"デバッガー拡張機能でサポートされている Python の最小バージョンは 3.9 です。","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"2020 年 5 月 1 日に非推奨となった ptvsd (Python デバッガー) に接続されていることをお知らせします。[debugpy](https://aka.ms/migrateToDebugpy) に切り替えてください。","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"デバッグを開始する前に Python インタープリターを選択する必要があります。\n\nヒント: ステータス バーの [インタープリターの選択] をクリックします。","cwd:":"cwd:","enter-your-module-name":"enter-your-module-name"} diff --git a/pre-built/l10n/bundle.l10n.ko.json b/pre-built/l10n/bundle.l10n.ko.json new file mode 100644 index 00000000..835df7d9 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.ko.json @@ -0,0 +1 @@ +{"Attach to a local process":"로컬 프로세스에 연결","Attach to a remote debug server":"원격 디버그 서버에 연결","Attach to process":"프로세스에 연결","Attach using Process ID":"프로세스 ID를 사용하여 연결","Browse Files...":"파일 찾아보기...","Browse your file system to find a Python file.":"파일 시스템을 찾아 Python 파일을 찾습니다.","Change Python Interpreter":"Python 인터프리터 변경","Command Line Arguments":"명령줄 인수","Debug Configuration":"디버그 구성","Debug Django":"Django 디버그","Debug FastAPI":"FastAPI 디버그","Debug Flask":"Flask 디버그","Debug Module":"디버그 모듈","Debug Pyramid":"Pyramid 디버그","Debug Stopped":"디버그 중지됨","Debug a Python module by invoking it with '-m'":"'-m'을 사용하여 Python 모듈을 호출하여 디버그","Debug the currently active Python file":"현재 활성 Python 파일 디버그","Debug the currently active Python file with arguments":"인수를 사용하는 현재 활성 Python 파일 디버그","Django":"Django","Do not show again":"다시 표시 안 함","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"터미널에서 [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), 'debugpy '을 사용하도록 설정합니다.","Enter a Python module/package name":"Python 모듈/패키지 이름 입력","Enter a valid file path":"올바른 파일 경로를 입력하세요.","Enter a valid host name or IP address":"올바른 호스트 이름 또는 IP 주소 입력","Enter a valid module name":"올바른 모듈 이름 입력","Enter a valid name":"올바른 이름을 입력하세요.","Enter a valid port number":"올바른 포트 번호를 입력하세요.","Enter the command line arguments you want to pass to the program":"프로그램에 전달하려는 명령줄 인수 입력","Enter the path to app.py or select a file from the list.":"app.py 경로를 입력하거나 목록에서 파일을 선택하세요.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"development.ini의 경로를 입력하세요({0}은(는) 현재 작업 영역 폴더의 루트를 가리킴)","Enter the path to manage.py or select a file from the list.":"manage.py 경로를 입력하거나 목록에서 파일을 선택하세요.","Enter the path to the application, e.g. 'main.py' or 'main'":"애플리케이션의 경로(예: 'main.py' 또는 'main')를 입력합니다.","Enter the port number that the debug server is listening on":"디버그 서버가 수신 대기 중인 포트 번호를 입력합니다.","Failed to launch debugger for child process {0}":"하위 프로세스 {0}에 대한 디버거를 시작하지 못했습니다.","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Django 웹 애플리케이션 시작 및 디버그","Launch and debug a FastAPI web application":"FastAPI 웹 애플리케이션 시작 및 디버그","Launch and debug a Flask web application":"Flask 웹 애플리케이션 시작 및 디버그","Launch and debug a Pyramid web application":"피라미드 웹 애플리케이션 시작 및 디버그","Module":"모듈","More Info":"추가 정보","No process selected":"선택한 프로세스가 없음","No, I will do it later":"아니요, 나중에 수행하겠습니다.","Open launch.json":"launch.json 열기","Operating system '{0}' not supported.":"운영 체제 '{0}'은(는) 지원되지 않습니다.","Pyramid":"피라미드형","Python Debugger":"Python 디버거","Python Debugger extension loading...":"Python 디버거 확장 로드 중...","Python Debugger: Attach using Process Id":"Python 디버거: 프로세스 ID를 사용하여 연결","Python Debugger: Current File":"Python 디버거: 현재 파일","Python Debugger: Current File with Arguments":"Python 디버거: 인수가 있는 현재 파일","Python Debugger: Django":"Python 디버거: Django","Python Debugger: FastAPI":"Python 디버거: FastAPI","Python Debugger: Flask":"Python 디버거: Flask","Python Debugger: Module":"Python 디버거: 모듈","Python Debugger: Pyramid Application":"Python 디버거: 피라미드형 애플리케이션","Python Debugger: Remote Attach":"Python 디버거: 원격 연결","Python File":"Python 파일","Python File with Arguments":"인수를 사용하는 Python 파일","Refresh process list":"프로세스 목록형 새로 고침","Remote Attach":"원격 연결","Remote Debugging":"원격 디버깅","Select File":"파일 선택","Select Python File":"Python 파일 선택","Select Python Interpreter":"Python 인터프리터 선택","Select a Python Debugger debug configuration":"Python 디버거 디버그 구성 선택","Select a debug configuration":"디버그 구성 선택","Select the process to attach to":"연결할 프로세스 선택","Show as Hex":"16진수로 표시","The minimum supported Python version for the debugger extension is 3.9.":"디버거 확장에 대한 최소 지원 Python 버전은 3.9입니다.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"2020년 5월 1일자로 더 이상 사용되지 않는 ptvsd(Python 디버거)에 연결하고 있는 것으로 나타났습니다. [debugpy](https://aka.ms/migrateToDebugpy)로 전환하세요.","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"디버깅을 시작하기 전에 Python 인터프리터를 선택해야 합니다.\n\n팁: 상태 표시줄에서 \"인터프리터 선택\"을 클릭하세요.","cwd:":"cwd:","enter-your-module-name":"enter-your-module-name"} diff --git a/pre-built/l10n/bundle.l10n.pl.json b/pre-built/l10n/bundle.l10n.pl.json new file mode 100644 index 00000000..2a89fc28 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.pl.json @@ -0,0 +1 @@ +{"Attach to a local process":"Dołącz do procesu lokalnego","Attach to a remote debug server":"Dołączanie do zdalnego serwera debugowania","Attach to process":"Dołącz do procesu","Attach using Process ID":"Dołącz przy użyciu identyfikatora procesu","Browse Files...":"Przeglądaj pliki...","Browse your file system to find a Python file.":"Przeglądaj system plików, aby znaleźć plik w języku Python.","Change Python Interpreter":"Zmień interpreter języka Python","Command Line Arguments":"Argumenty wiersza polecenia","Debug Configuration":"Konfiguracja debugowania","Debug Django":"Debugowanie struktury Django","Debug FastAPI":"Debuguj FastAPI","Debug Flask":"Debuguj strukturę Flask","Debug Module":"Moduł debugowania","Debug Pyramid":"Debuguj aplikację Piramida","Debug Stopped":"Zatrzymano debugowanie","Debug a Python module by invoking it with '-m'":"Debugowanie modułu języka Python przez wywołanie go za pomocą polecenia „-m”","Debug the currently active Python file":"Debugowanie aktualnie aktywnego pliku języka Python","Debug the currently active Python file with arguments":"Debugowanie aktualnie aktywnego pliku języka Python z argumentami","Django":"Django","Do not show again":"Nie pokazuj ponownie","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Umożliwia korzystanie z [debugowania bez konfiguracji](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy ` w terminalu.","Enter a Python module/package name":"Wprowadź nazwę modułu/pakietu języka Python","Enter a valid file path":"Wprowadź prawidłową ścieżkę pliku","Enter a valid host name or IP address":"Wprowadź prawidłową nazwę hosta lub prawidłowy adres IP","Enter a valid module name":"Wprowadź prawidłową nazwę modułu","Enter a valid name":"Wprowadź prawidłową nazwę","Enter a valid port number":"Wprowadź prawidłowy numer portu","Enter the command line arguments you want to pass to the program":"Wprowadź argumenty wiersza polecenia, które chcesz przekazać do programu","Enter the path to app.py or select a file from the list.":"Wprowadź ścieżkę do app.py lub wybierz plik z listy.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Wprowadź ścieżkę do pliku development.ini ({0} wskazuje katalog główny bieżącego folderu obszaru roboczego)","Enter the path to manage.py or select a file from the list.":"Wprowadź ścieżkę do manage.py lub wybierz plik z listy.","Enter the path to the application, e.g. 'main.py' or 'main'":"Wprowadź ścieżkę do aplikacji, np. „main.py” lub „main”","Enter the port number that the debug server is listening on":"Wprowadź numer portu, na który nasłuchuje serwer debugowania","Failed to launch debugger for child process {0}":"Nie można uruchomić debugera dla procesu podrzędnego {0}","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Uruchamianie i debugowanie aplikacji internetowej Django","Launch and debug a FastAPI web application":"Uruchamianie i debugowanie aplikacji internetowej FastAPI","Launch and debug a Flask web application":"Uruchom i debuguj aplikację internetową Flask","Launch and debug a Pyramid web application":"Uruchamianie i debugowanie aplikacji internetowej Pyramid","Module":"Moduł","More Info":"Więcej informacji","No process selected":"Nie wybrano żadnego procesu","No, I will do it later":"Nie, zrobię to później","Open launch.json":"Otwórz plik launch.json","Operating system '{0}' not supported.":"System operacyjny „{0}” nie jest obsługiwany.","Pyramid":"Piramida","Python Debugger":"Debuger języka Python","Python Debugger extension loading...":"Ładowanie rozszerzenia debuggera języka Python...","Python Debugger: Attach using Process Id":"Debuger języka Python: Dołącz przy użyciu identyfikatora procesu","Python Debugger: Current File":"Debuger języka Python: Current File","Python Debugger: Current File with Arguments":"Debuger języka Python: Debugpy: bieżący plik z argumentami","Python Debugger: Django":"Debuger języka Python: Django","Python Debugger: FastAPI":"Debuger języka Python: FastAPI","Python Debugger: Flask":"Debuger języka Python: Flask","Python Debugger: Module":"Debuger języka Python: Moduł","Python Debugger: Pyramid Application":"Debuger języka Python: Aplikacja Piramida","Python Debugger: Remote Attach":"Debuger języka Python: Dołączanie zdalne","Python File":"Plik języka Python","Python File with Arguments":"Plik języka Python z argumentami","Refresh process list":"Odśwież listę procesów","Remote Attach":"Dołączanie zdalne","Remote Debugging":"Debugowanie zdalne","Select File":"Wybierz plik","Select Python File":"Wybierz plik języka Python","Select Python Interpreter":"Wybierz interpreter języka Python","Select a Python Debugger debug configuration":"Wybierz konfigurację debugowania dla debugera języka Python","Select a debug configuration":"Wybierz konfigurację debugowania","Select the process to attach to":"Wybierz docelowy proces dołączania","Show as Hex":"Pokaż jako szesnastkowy","The minimum supported Python version for the debugger extension is 3.9.":"Minimalna wersja języka Python obsługiwana przez rozszerzenie debugera to 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Zauważyliśmy, że dołączasz do narzędzia ptvsd (debuger języka Python), który został wycofany 1 maja 2020 r. Przełącz się na [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Przed rozpoczęciem debugowania musisz wybrać interpreter języka Python.\n\nPorada: kliknij pozycję „Select Interpreter” (Wybierz interpreter) na pasku stanu.","cwd:":"Cwd:","enter-your-module-name":"wprowadź nazwę modułu"} diff --git a/pre-built/l10n/bundle.l10n.pt-br.json b/pre-built/l10n/bundle.l10n.pt-br.json new file mode 100644 index 00000000..6893bdd9 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.pt-br.json @@ -0,0 +1 @@ +{"Attach to a local process":"Anexar a um processo local","Attach to a remote debug server":"Anexar a um servidor de depuração remoto","Attach to process":"Anexar ao processo","Attach using Process ID":"Anexar usando a ID do Processo","Browse Files...":"Procurar arquivos...","Browse your file system to find a Python file.":"Navegue pelo sistema de arquivos para localizar um arquivo Python.","Change Python Interpreter":"Alterar o Interpretador Python","Command Line Arguments":"Argumentos de Linha de Comando","Debug Configuration":"Configuração da Depuração","Debug Django":"Depurar Django","Debug FastAPI":"Depurar FastAPI","Debug Flask":"Depurar Flask","Debug Module":"Módulo de Depuração","Debug Pyramid":"Depurar Pyramid","Debug Stopped":"Depuração Interrompida","Debug a Python module by invoking it with '-m'":"Depurar um módulo Python invocando-o com '-m'","Debug the currently active Python file":"Depurar o arquivo Python ativo no momento","Debug the currently active Python file with arguments":"Depurar o arquivo Python ativo no momento com argumentos","Django":"Django","Do not show again":"Não mostrar novamente","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Habilita o uso de [depuração sem configuração](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, no terminal.","Enter a Python module/package name":"Insira um nome para o módulo/pacote Python","Enter a valid file path":"Insira um caminho do arquivo válido.","Enter a valid host name or IP address":"Insira um nome de host válido ou endereço IP","Enter a valid module name":"Insira um nome de módulo válido","Enter a valid name":"Insira um nome válido.","Enter a valid port number":"Insira um número de porta válido.","Enter the command line arguments you want to pass to the program":"Insira os argumentos de linha de comando que você deseja passar para o programa","Enter the path to app.py or select a file from the list.":"Insira o caminho para app.py ou selecione um arquivo da lista.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Digite o caminho para development.ini ({0} aponta para a raiz da pasta do espaço de trabalho atual)","Enter the path to manage.py or select a file from the list.":"Insira o caminho para manage.py ou selecione um arquivo da lista.","Enter the path to the application, e.g. 'main.py' or 'main'":"Insira o caminho para o aplicativo, por exemplo, 'main.py' ou 'main'","Enter the port number that the debug server is listening on":"Insira o número da porta que o servidor de depuração está escutando","Failed to launch debugger for child process {0}":"Falha ao iniciar o depurador para o processo filho {0}","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Iniciar e depurar um aplicativo Web Django","Launch and debug a FastAPI web application":"Iniciar e depurar um aplicativo Web FastAPI","Launch and debug a Flask web application":"Iniciar e depurar um aplicativo Web Flask","Launch and debug a Pyramid web application":"Iniciar e depurar um aplicativo Web Pyramid","Module":"Módulo","More Info":"Mais Informações","No process selected":"Nenhum processo selecionado","No, I will do it later":"Não, farei isso mais tarde","Open launch.json":"Abrir launch.json","Operating system '{0}' not supported.":"O sistema operacional '{0}' não é suportado.","Pyramid":"Pyramid","Python Debugger":"Depurador do Python","Python Debugger extension loading...":"Carregando a extensão do Depurador do Python...","Python Debugger: Attach using Process Id":"Depurador do Python: Anexar usando o ID do Processo","Python Debugger: Current File":"Depurador do Python: Arquivo Atual","Python Debugger: Current File with Arguments":"Depurador do Python: Arquivo atual com argumentos","Python Debugger: Django":"Depurador do Python: Django","Python Debugger: FastAPI":"Depurador do Python: FastAPI","Python Debugger: Flask":"Depurador do Python: Flask","Python Debugger: Module":"Depurador do Python: Módulo","Python Debugger: Pyramid Application":"Depurador do Python: Aplicativo Pyramid","Python Debugger: Remote Attach":"Depurador do Python: Anexação Remota","Python File":"Arquivo Python","Python File with Arguments":"Arquivo Python com Argumentos","Refresh process list":"Atualizar a lista de processos","Remote Attach":"Anexação Remota","Remote Debugging":"Depuração Remota","Select File":"Selecionar Arquivo","Select Python File":"Selecionar Arquivo Python","Select Python Interpreter":"Selecionar Interpretador do Python","Select a Python Debugger debug configuration":"Selecione uma configuração de depuração do Python Debugger","Select a debug configuration":"Selecionar uma configuração de depuração","Select the process to attach to":"Selecione o processo ao qual anexar","Show as Hex":"Mostrar como Hexadecimal","The minimum supported Python version for the debugger extension is 3.9.":"A versão mínima suportada do Python para a extensão do depurador é 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Notamos que você está anexando ao ptvsd (depurador do Python), que foi preterido em 1º de maio de 2020. Mude para [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Você precisa selecionar um interpretador Python antes de iniciar a depuração.\n\nDica: clique em “Selecionar Interpretador” na barra de status.","cwd:":"cwd:","enter-your-module-name":"enter-your-module-name"} diff --git a/pre-built/l10n/bundle.l10n.qps-ploc.json b/pre-built/l10n/bundle.l10n.qps-ploc.json new file mode 100644 index 00000000..ae0001bd --- /dev/null +++ b/pre-built/l10n/bundle.l10n.qps-ploc.json @@ -0,0 +1 @@ +{"Attach to a local process":"Ættæçh tø æ løçæl prøçëss","Attach to a remote debug server":"Ættæçh tø æ rëmøtë ðëþµg sërvër","Attach to process":"Ættæçh tø prøçëss","Attach using Process ID":"Ættæçh µsïñg Prøçëss ÏÐ","Browse Files...":"ßrøwsë Fïlës...","Browse your file system to find a Python file.":"ßrøwsë ÿøµr fïlë sÿstëm tø fïñð æ Pÿthøñ fïlë.","Change Python Interpreter":"Çhæñgë Pÿthøñ Ïñtërprëtër","Command Line Arguments":"Çømmæñð £ïñë Ærgµmëñts","Debug Configuration":"Ðëþµg Çøñfïgµrætïøñ","Debug Django":"Ðëþµg Ðjæñgø","Debug FastAPI":"Ðëþµg FæstÆPÏ","Debug Flask":"Ðëþµg Flæsk","Debug Module":"Ðëþµg Møðµlë","Debug Pyramid":"Ðëþµg Pÿræmïð","Debug Stopped":"Ðëþµg §tøppëð","Debug a Python module by invoking it with '-m'":"Ðëþµg æ Pÿthøñ møðµlë þÿ ïñvøkïñg ït wïth '-m'","Debug the currently active Python file":"Ðëþµg thë çµrrëñtlÿ æçtïvë Pÿthøñ fïlë","Debug the currently active Python file with arguments":"Ðëþµg thë çµrrëñtlÿ æçtïvë Pÿthøñ fïlë wïth ærgµmëñts","Django":"Ðjæñgø","Do not show again":"Ðø ñøt shøw ægæïñ","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Ëñæþlës µsë øf [ñø-çøñfïg ðëþµggïñg](https://gïthµþ.çøm/mïçrøsøft/vsçøðë-pÿthøñ-ðëþµggër/wïkï/Ñø%Ë2%80%90Çøñfïg-Ðëþµggïñg), `ðëþµgpÿ `, ïñ thë tërmïñæl.","Enter a Python module/package name":"Ëñtër æ Pÿthøñ møðµlë/pæçkægë ñæmë","Enter a valid file path":"Ëñtër æ vælïð fïlë pæth","Enter a valid host name or IP address":"Ëñtër æ vælïð høst ñæmë ør ÏP æððrëss","Enter a valid module name":"Ëñtër æ vælïð møðµlë ñæmë","Enter a valid name":"Ëñtër æ vælïð ñæmë","Enter a valid port number":"Ëñtër æ vælïð pørt ñµmþër","Enter the command line arguments you want to pass to the program":"Ëñtër thë çømmæñð lïñë ærgµmëñts ÿøµ wæñt tø pæss tø thë prøgræm","Enter the path to app.py or select a file from the list.":"Ëñtër thë pæth tø æpp.pÿ ør sëlëçt æ fïlë frøm thë lïst.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Ëñtër thë pæth tø ðëvëløpmëñt.ïñï ({0} pøïñts tø thë røøt øf thë çµrrëñt wørkspæçë følðër)","Enter the path to manage.py or select a file from the list.":"Ëñtër thë pæth tø mæñægë.pÿ ør sëlëçt æ fïlë frøm thë lïst.","Enter the path to the application, e.g. 'main.py' or 'main'":"Ëñtër thë pæth tø thë æpplïçætïøñ, ë.g. 'mæïñ.pÿ' ør 'mæïñ'","Enter the port number that the debug server is listening on":"Ëñtër thë pørt ñµmþër thæt thë ðëþµg sërvër ïs lïstëñïñg øñ","Failed to launch debugger for child process {0}":"Fæïlëð tø læµñçh ðëþµggër før çhïlð prøçëss {0}","FastAPI":"FæstÆPÏ","Flask":"Flæsk","Launch and debug a Django web application":"£æµñçh æñð ðëþµg æ Ðjæñgø wëþ æpplïçætïøñ","Launch and debug a FastAPI web application":"£æµñçh æñð ðëþµg æ FæstÆPÏ wëþ æpplïçætïøñ","Launch and debug a Flask web application":"£æµñçh æñð ðëþµg æ Flæsk wëþ æpplïçætïøñ","Launch and debug a Pyramid web application":"£æµñçh æñð ðëþµg æ Pÿræmïð wëþ æpplïçætïøñ","Module":"Møðµlë","More Info":"Mørë Ïñfø","No process selected":"Ñø prøçëss sëlëçtëð","No, I will do it later":"Ñø, Ï wïll ðø ït lætër","Open launch.json":"Øpëñ læµñçh.jsøñ","Operating system '{0}' not supported.":"Øpërætïñg sÿstëm '{0}' ñøt sµppørtëð.","Pyramid":"Pÿræmïð","Python Debugger":"Pÿthøñ Ðëþµggër","Python Debugger extension loading...":"Pÿthøñ Ðëþµggër ëxtëñsïøñ løæðïñg...","Python Debugger: Attach using Process Id":"Pÿthøñ Ðëþµggër: Ættæçh µsïñg Prøçëss Ïð","Python Debugger: Current File":"Pÿthøñ Ðëþµggër: ǵrrëñt Fïlë","Python Debugger: Current File with Arguments":"Pÿthøñ Ðëþµggër: ǵrrëñt Fïlë wïth Ærgµmëñts","Python Debugger: Django":"Pÿthøñ Ðëþµggër: Ðjæñgø","Python Debugger: FastAPI":"Pÿthøñ Ðëþµggër: FæstÆPÏ","Python Debugger: Flask":"Pÿthøñ Ðëþµggër: Flæsk","Python Debugger: Module":"Pÿthøñ Ðëþµggër: Møðµlë","Python Debugger: Pyramid Application":"Pÿthøñ Ðëþµggër: Pÿræmïð Æpplïçætïøñ","Python Debugger: Remote Attach":"Pÿthøñ Ðëþµggër: Rëmøtë Ættæçh","Python File":"Pÿthøñ Fïlë","Python File with Arguments":"Pÿthøñ Fïlë wïth Ærgµmëñts","Refresh process list":"Rëfrësh prøçëss lïst","Remote Attach":"Rëmøtë Ættæçh","Remote Debugging":"Rëmøtë Ðëþµggïñg","Select File":"§ëlëçt Fïlë","Select Python File":"§ëlëçt Pÿthøñ Fïlë","Select Python Interpreter":"§ëlëçt Pÿthøñ Ïñtërprëtër","Select a Python Debugger debug configuration":"§ëlëçt æ Pÿthøñ Ðëþµggër ðëþµg çøñfïgµrætïøñ","Select a debug configuration":"§ëlëçt æ ðëþµg çøñfïgµrætïøñ","Select the process to attach to":"§ëlëçt thë prøçëss tø ættæçh tø","Show as Hex":"§høw æs Hëx","The minimum supported Python version for the debugger extension is 3.9.":"Thë mïñïmµm sµppørtëð Pÿthøñ vërsïøñ før thë ðëþµggër ëxtëñsïøñ ïs 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Wë ñøtïçëð ÿøµ ærë ættæçhïñg tø ptvsð (Pÿthøñ ðëþµggër), whïçh wæs ðëprëçætëð øñ Mæÿ 1st, 2020. Plëæsë swïtçh tø [ðëþµgpÿ](https://ækæ.ms/mïgrætëTøÐëþµgpÿ).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Ýøµ ñëëð tø sëlëçt æ Pÿthøñ ïñtërprëtër þëførë ÿøµ stært ðëþµggïñg.\n\nTïp: çlïçk øñ \"§ëlëçt Ïñtërprëtër\" ïñ thë stætµs þær.","cwd:":"çwð:","enter-your-module-name":"ëñtër-ÿøµr-møðµlë-ñæmë"} diff --git a/pre-built/l10n/bundle.l10n.ru.json b/pre-built/l10n/bundle.l10n.ru.json new file mode 100644 index 00000000..6960c0c3 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.ru.json @@ -0,0 +1 @@ +{"Attach to a local process":"Подключить к локальному процессу","Attach to a remote debug server":"Присоединение к удаленному серверу отладки","Attach to process":"Присоединиться к процессу","Attach using Process ID":"Подключить с помощью идентификатора процесса","Browse Files...":"Обзор файлов...","Browse your file system to find a Python file.":"Просмотрите файловую систему, чтобы найти файл Python.","Change Python Interpreter":"Изменить интерпретатор Python","Command Line Arguments":"Аргументы командной строки","Debug Configuration":"Конфигурация отладки","Debug Django":"Отладка Django","Debug FastAPI":"Отладка FastAPI","Debug Flask":"Отладка Flask","Debug Module":"Модуль отладки","Debug Pyramid":"Пирамида отладки","Debug Stopped":"Отладка остановлена","Debug a Python module by invoking it with '-m'":"Отладка модуля Python путем его вызова с помощью «-m»","Debug the currently active Python file":"Отладка текущего активного файла Python","Debug the currently active Python file with arguments":"Отладка текущего активного файла Python с аргументами","Django":"Django","Do not show again":"Больше не показывать","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Включает использование [отладки без конфигурации](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging) \"debugpy \" в терминале.","Enter a Python module/package name":"Введите имя модуля или пакета Python","Enter a valid file path":"Введите допустимый путь к файлу","Enter a valid host name or IP address":"Ввод допустимого имени или IP-адреса узла","Enter a valid module name":"Введите допустимое имя модуля","Enter a valid name":"Введите допустимое имя","Enter a valid port number":"Введите допустимый номер порта","Enter the command line arguments you want to pass to the program":"Введите аргументы командной строки, которые вы хотите передать программе.","Enter the path to app.py or select a file from the list.":"Введите путь к app.py или выберите файл из списка.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Введите путь к development.ini ({0}указывает на корень папки текущей рабочей области)","Enter the path to manage.py or select a file from the list.":"Введите путь к manage.py или выберите файл из списка.","Enter the path to the application, e.g. 'main.py' or 'main'":"Введите путь к приложению, например «main.py» или «main»","Enter the port number that the debug server is listening on":"Введите номер порта, который прослушивает сервер отладки","Failed to launch debugger for child process {0}":"Не удалось запустить отладчик для дочернего процесса {0}","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Запуск и отладка веб-приложения Django","Launch and debug a FastAPI web application":"Запуск и отладка веб-приложения FastAPI","Launch and debug a Flask web application":"Запуск и отладка веб-приложения Flask","Launch and debug a Pyramid web application":"Запуск и отладка веб-приложения Pyramid","Module":"Модуль","More Info":"Дополнительные сведения","No process selected":"Процесс не выбран","No, I will do it later":"Нет, выполню позже","Open launch.json":"Открыть launch.json","Operating system '{0}' not supported.":"Операционная система «{0}» не поддерживается.","Pyramid":"Пирамида","Python Debugger":"Отладчик Python","Python Debugger extension loading...":"Загрузка расширения отладчика Python...","Python Debugger: Attach using Process Id":"Отладчик Python: Подключить с помощью идентификатора процесса","Python Debugger: Current File":"Отладчик Python: Текущий файл","Python Debugger: Current File with Arguments":"Отладчик Python: Текущий файл с аргументами","Python Debugger: Django":"Отладчик Python: Django","Python Debugger: FastAPI":"Отладчик Python: FastAPI","Python Debugger: Flask":"Отладчик Python: Flask","Python Debugger: Module":"Отладчик Python: Модуль","Python Debugger: Pyramid Application":"Отладчик Python: Приложение Pyramid","Python Debugger: Remote Attach":"Отладчик Python: Удаленное подключение","Python File":"Файл Python","Python File with Arguments":"Файл Python с аргументами","Refresh process list":"Обновить список процессов","Remote Attach":"Удаленное подключение","Remote Debugging":"Удаленная отладка","Select File":"Выберите файл","Select Python File":"Выбор файла Python","Select Python Interpreter":"Выбор интерпретатора Python","Select a Python Debugger debug configuration":"Выберите конфигурацию отладки отладчика Python","Select a debug configuration":"Выбрать конфигурацию отладки","Select the process to attach to":"Выберите процесс, к которому нужно выполнить подключение","Show as Hex":"Показать как шестнадцатеричный","The minimum supported Python version for the debugger extension is 3.9.":"Минимально поддерживаемая версия Python для расширения отладчика — 3.9.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"Мы заметили, что вы подключаетесь к ptvsd (отладчику Python), который устарел 1 мая 2020 года. Переключитесь на [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Перед началом отладки необходимо выбрать интерпретатор Python.\n\nСовет: нажмите \"Выбор интерпретатора\" в строке состояния.","cwd:":"Cwd:","enter-your-module-name":"enter-your-module-name"} diff --git a/pre-built/l10n/bundle.l10n.tr.json b/pre-built/l10n/bundle.l10n.tr.json new file mode 100644 index 00000000..adcdd2ad --- /dev/null +++ b/pre-built/l10n/bundle.l10n.tr.json @@ -0,0 +1 @@ +{"Attach to a local process":"Yerel işleme ekle","Attach to a remote debug server":"Uzaktan hata ayıklama sunucusuna ekle","Attach to process":"İşleme ekle","Attach using Process ID":"İşlem Kimliği kullanarak ekle","Browse Files...":"Dosyalara Göz At...","Browse your file system to find a Python file.":"Python dosyasını bulmak için dosya sisteminize göz atın.","Change Python Interpreter":"Python Yorumlayıcısını Değiştir","Command Line Arguments":"Komut Satırı Bağımsız Değişkenleri","Debug Configuration":"Hata Ayıklama Yapılandırması","Debug Django":"Django’da Hata Ayıkla","Debug FastAPI":"FastAPI'da Hata Ayıkla","Debug Flask":"Flask'te Hata Ayıkla","Debug Module":"Hata Ayıklama Modülü","Debug Pyramid":"Pyramid’de Hata Ayıklama","Debug Stopped":"Hata Ayıklama Durduruldu","Debug a Python module by invoking it with '-m'":"Python modülünü '-m' ile çağırarak hata ayıklayın","Debug the currently active Python file":"Şu anda etkin olan Python dosyasında hata ayıkla","Debug the currently active Python file with arguments":"Şu anda etkin olan ve bağımsız değişkenler içeren Python dosyasında hata ayıklayın","Django":"Django","Do not show again":"Tekrar gösterme","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"Terminalde [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), 'debugpy ' kullanımına izin ver.","Enter a Python module/package name":"Python modülü/paketi adını girin","Enter a valid file path":"Geçerli bir dosya yolu girin","Enter a valid host name or IP address":"Geçerli bir ana bilgisayar adı veya IP adresi girin","Enter a valid module name":"Geçerli bir modül adı girin","Enter a valid name":"Geçerli bir ad girin","Enter a valid port number":"Geçerli bir bağlantı noktası numarası girin","Enter the command line arguments you want to pass to the program":"Programa geçirmek istediğiniz komut satırı bağımsız değişkenlerini girin","Enter the path to app.py or select a file from the list.":"app.py dosyasının yolunu girin veya listeden bir dosya seçin.","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"Development.ini yolunu girin ({0}, geçerli çalışma alanı klasörünün kökünü belirtir)","Enter the path to manage.py or select a file from the list.":"manage.py dosyasının yolunu girin veya listeden bir dosya seçin.","Enter the path to the application, e.g. 'main.py' or 'main'":"Uygulamanın yolunu girin, örneğin 'main.py' veya 'main'","Enter the port number that the debug server is listening on":"Hata ayıklama sunucusunun dinlediği bağlantı noktasının numarasını girin","Failed to launch debugger for child process {0}":"Alt işlem {0} için hata ayıklayıcısı başlatılamadı","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"Django web uygulamasını başlat ve hata ayıkla","Launch and debug a FastAPI web application":"FastAPI web uygulamasını başlat ve hata ayıkla","Launch and debug a Flask web application":"Flask web uygulamasını başlat ve hata ayıkla","Launch and debug a Pyramid web application":"Pyramid web uygulamasını başlat ve hata ayıkla","Module":"Modül","More Info":"Daha Fazla Bilgi","No process selected":"İşlem seçilmedi","No, I will do it later":"Hayır, daha sonra yapacağım","Open launch.json":"launch.json dosyasını aç","Operating system '{0}' not supported.":"‘{0}’ işletim sistemi desteklenmiyor.","Pyramid":"Piramit","Python Debugger":"Python Hata Ayıklayıcısı","Python Debugger extension loading...":"Python Hata Ayıklayıcı uzantısı yükleniyor...","Python Debugger: Attach using Process Id":"Python Hata Ayıklayıcısı: İşlem Kimliği kullanarak ekle","Python Debugger: Current File":"Python Hata Ayıklayıcısı: Geçerli Dosya","Python Debugger: Current File with Arguments":"Python Hata Ayıklayıcısı: Bağımsız Değişkenler içeren Geçerli Dosya","Python Debugger: Django":"Python Hata Ayıklayıcısı: Django","Python Debugger: FastAPI":"Python Hata Ayıklayıcısı: FastAPI","Python Debugger: Flask":"Python Hata Ayıklayıcısı: Flask","Python Debugger: Module":"Python Hata Ayıklayıcısı: Modül","Python Debugger: Pyramid Application":"Python Hata Ayıklayıcısı: Piramit Uygulaması","Python Debugger: Remote Attach":"Python Hata Ayıklayıcısı: Uzaktan Ekleme","Python File":"Python Dosyası","Python File with Arguments":"Bağımsız Değişkenler içeren Python Dosyası","Refresh process list":"İşlem listesini yenile","Remote Attach":"Uzaktan Ekleme","Remote Debugging":"Uzaktan Hata Ayıklama","Select File":"Dosya Seç","Select Python File":"Python Dosyası Seç","Select Python Interpreter":"Python Yorumlayıcısını seçin","Select a Python Debugger debug configuration":"Python Hata Ayıklayıcısı hata ayıklama yapılandırması seçin","Select a debug configuration":"Bir hata ayıklama yapılandırması seçin","Select the process to attach to":"Eklenilecek işlemi seçin","Show as Hex":"Onaltılık olarak göster","The minimum supported Python version for the debugger extension is 3.9.":"Hata ayıklayıcı uzantısı için desteklenen en düşük Python sürümü 3.9'dur.","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"1 Mayıs 2020'de kullanım dışı bırakılan ptvsd'ye (Python hata ayıklayıcısı) eklediğinizi algıladık. Lütfen [debugpy](https://aka.ms/migrateToDebugpy)’a geçiş yapın.","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"Hata ayıklamaya başlamadan önce bir Python yorumlayıcısı seçmeniz gerekir.\n\nİpucu: durum çubuğunda \"Yorumlayıcı Seç\"e tıklayın.","cwd:":"cwd:","enter-your-module-name":"modül adınızı girin"} diff --git a/pre-built/l10n/bundle.l10n.zh-cn.json b/pre-built/l10n/bundle.l10n.zh-cn.json new file mode 100644 index 00000000..63361be2 --- /dev/null +++ b/pre-built/l10n/bundle.l10n.zh-cn.json @@ -0,0 +1 @@ +{"Attach to a local process":"附加到本地进程","Attach to a remote debug server":"附加到远程调试服务器","Attach to process":"附加到进程","Attach using Process ID":"使用进程 ID 进行附加","Browse Files...":"浏览文件...","Browse your file system to find a Python file.":"浏览文件系统以查找 Python 文件。","Change Python Interpreter":"更改 Python 解释器","Command Line Arguments":"命令行参数","Debug Configuration":"调试配置","Debug Django":"调试 Django 应用程序","Debug FastAPI":"调试 FastAPI","Debug Flask":"调试 Flask","Debug Module":"调试模块","Debug Pyramid":"调试 Pyramid","Debug Stopped":"调试已停止","Debug a Python module by invoking it with '-m'":"通过使用 \\\"-m\\\" 调用 Python 模块来调试它","Debug the currently active Python file":"调试当前正在运行的 Python 文件","Debug the currently active Python file with arguments":"使用参数调试当前活动的 Python 文件","Django":"Django","Do not show again":"不再显示","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"允许在终端中使用 [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), “debugpy ”。","Enter a Python module/package name":"输入 Python 模块/包名称","Enter a valid file path":"输入有效的文件路径","Enter a valid host name or IP address":"输入有效主机名或 IP 地址","Enter a valid module name":"输入有效的模块名称","Enter a valid name":"输入有效名称","Enter a valid port number":"请输入一个有效的端口号。","Enter the command line arguments you want to pass to the program":"输入要传递给程序的命令行参数","Enter the path to app.py or select a file from the list.":"输入 app.py 的路径或从列表中选择文件。","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"输入 development.ini 的路径({0} 指向当前工作区文件夹的根目录)","Enter the path to manage.py or select a file from the list.":"输入 manage.py 的路径或从列表中选择文件。","Enter the path to the application, e.g. 'main.py' or 'main'":"请输入应用程序的路径,例如 \\\"main.py\\\" 或 \\\"main\\\"","Enter the port number that the debug server is listening on":"输入调试服务器正在侦听的端口号","Failed to launch debugger for child process {0}":"无法为子进程 {0} 启动调试器","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"启动和调试 Django Web 应用程序","Launch and debug a FastAPI web application":"启动和调试 FastAPI Web 应用程序","Launch and debug a Flask web application":"启动和调试 Flask Web 应用程序","Launch and debug a Pyramid web application":"启动和调试 Pyramid Web 应用程序","Module":"模块","More Info":"详细信息","No process selected":"未选择进程","No, I will do it later":"否,我将稍后执行此操作","Open launch.json":"打开 launch.json","Operating system '{0}' not supported.":"不支持操作系统“{0}”。","Pyramid":"Pyramid","Python Debugger":"Python 调试程序","Python Debugger extension loading...":"正在加载 Python 调试器扩展...","Python Debugger: Attach using Process Id":"Python 调试程序: 使用进程 ID 附加","Python Debugger: Current File":"Python 调试程序: 当前文件","Python Debugger: Current File with Arguments":"Python 调试程序: 包含参数的当前文件","Python Debugger: Django":"Python 调试程序: Django","Python Debugger: FastAPI":"Python 调试程序: FastAPI","Python Debugger: Flask":"Python 调试程序: Flask","Python Debugger: Module":"Python 调试程序: 模块","Python Debugger: Pyramid Application":"Python 调试程序: Pyramid 应用程序","Python Debugger: Remote Attach":"Python 调试程序: 远程附加","Python File":"Python 文件","Python File with Arguments":"带有参数的 Python 文件","Refresh process list":"刷新进程列表","Remote Attach":"远程附加","Remote Debugging":"远程调试","Select File":"选择文件","Select Python File":"选择 Python 文件","Select Python Interpreter":"选择 Python 解释器","Select a Python Debugger debug configuration":"选择 Python 调试程序调试配置","Select a debug configuration":"选择调试配置","Select the process to attach to":"选择要附加到的进程","Show as Hex":"显示为十六进制","The minimum supported Python version for the debugger extension is 3.9.":"调试器扩展支持的最低 Python 版本是 3.9。","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"我们注意到你正在连接已于 2020 年 5 月 1 日被弃用的 ptvsd (Python 调试器)。请切换到 [debugpy](https://aka.ms/migrateToDebugpy)。","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"在开始调试之前,需要选择 Python 解释器。\n\n提示: 单击状态栏中的“选择解释器”。","cwd:":"cwd:","enter-your-module-name":"enter-your-module-name"} diff --git a/pre-built/l10n/bundle.l10n.zh-tw.json b/pre-built/l10n/bundle.l10n.zh-tw.json new file mode 100644 index 00000000..bde1a0ba --- /dev/null +++ b/pre-built/l10n/bundle.l10n.zh-tw.json @@ -0,0 +1 @@ +{"Attach to a local process":"附加到本機處理序","Attach to a remote debug server":"連結到遠端偵錯伺服器","Attach to process":"附加至處理序","Attach using Process ID":"使用處理程式識別碼附加","Browse Files...":"瀏覽檔案...","Browse your file system to find a Python file.":"瀏覽您的檔案系統以尋找 Python 檔案。","Change Python Interpreter":"變更 Python 解譯器","Command Line Arguments":"命令列的引數","Debug Configuration":"偵錯設定","Debug Django":"為 Django 進行偵錯","Debug FastAPI":"為 FastAPI 進行偵錯","Debug Flask":"為 Flask 進行偵錯","Debug Module":"為模組進行偵錯","Debug Pyramid":"為 Pyramid 進行偵錯","Debug Stopped":"偵錯已停止","Debug a Python module by invoking it with '-m'":"使用 '-m' 叫用 Python 模組來對其偵錯","Debug the currently active Python file":"偵錯目前使用中的 Python 檔案","Debug the currently active Python file with arguments":"使用引數對目前使用中的 Python 檔案進行偵錯","Django":"Django","Do not show again":"不要再顯示","Enables use of [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging), `debugpy `, in the terminal.":"啟用在終端機中使用 [no-config debugging](https://github.com/microsoft/vscode-python-debugger/wiki/No%E2%80%90Config-Debugging)、`debugpy `。","Enter a Python module/package name":"輸入 Python 模組/套件名稱","Enter a valid file path":"輸入有效的檔案路徑","Enter a valid host name or IP address":"輸入有效的主機名稱或 IP 位址","Enter a valid module name":"輸入有效的模組名稱","Enter a valid name":"請輸入有效的名稱。","Enter a valid port number":"請輸入有效的連接埠號碼。","Enter the command line arguments you want to pass to the program":"輸入您要傳遞給程式的命令列引數","Enter the path to app.py or select a file from the list.":"輸入要 app.py 的路徑,或從清單中選取檔案。","Enter the path to development.ini ({0} points to the root of the current workspace folder)":"輸入 development.ini 的路徑 ({0} 指向目前工作區資料夾的根目錄)","Enter the path to manage.py or select a file from the list.":"輸入要 manage.py 的路徑,或從清單中選取檔案。","Enter the path to the application, e.g. 'main.py' or 'main'":"輸入應用程式的路徑,例如 'main.py' 或 'main'","Enter the port number that the debug server is listening on":"輸入偵錯伺服器正在接聽的連接埠號碼","Failed to launch debugger for child process {0}":"無法為子處理序 {0} 啟動偵錯工具","FastAPI":"FastAPI","Flask":"Flask","Launch and debug a Django web application":"啟動 Django Web 應用程式並對其偵錯","Launch and debug a FastAPI web application":"啟動 FastAPI Web 應用程式並對其偵錯","Launch and debug a Flask web application":"啟動 Flask Web 應用程式並對其偵錯","Launch and debug a Pyramid web application":"啟動 Pyramid Web 應用程式並對其偵錯","Module":"模組","More Info":"更多資訊","No process selected":"未選取任何處理序","No, I will do it later":"否,我稍後會執行","Open launch.json":"開啟 launch.json","Operating system '{0}' not supported.":"不支援作業系統 '{0}'。","Pyramid":"Pyramid","Python Debugger":"Python 偵錯工具","Python Debugger extension loading...":"Python 偵錯工具延伸模載入中...","Python Debugger: Attach using Process Id":"Python 偵錯工具: 使用處理程式識別碼附加","Python Debugger: Current File":"Python 偵錯工具: 目前檔案","Python Debugger: Current File with Arguments":"Python 偵錯工具: 帶引數的目前檔案","Python Debugger: Django":"Python 偵錯工具: Django","Python Debugger: FastAPI":"Python 偵錯工具: FastAPI","Python Debugger: Flask":"Python 偵錯工具: Flask","Python Debugger: Module":"Python 偵錯工具: 模組","Python Debugger: Pyramid Application":"Python 偵錯工具: Pyramid Application","Python Debugger: Remote Attach":"Python 偵錯工具: 遠端附加","Python File":"Python 檔案","Python File with Arguments":"具有引數的 Python 檔案","Refresh process list":"重新整理處理序清單","Remote Attach":"遠端附加","Remote Debugging":"遠端偵錯","Select File":"選取檔案","Select Python File":"選取 Python 檔案","Select Python Interpreter":"選取 Python 解譯器","Select a Python Debugger debug configuration":"選取 Python 偵錯工具偵錯設定","Select a debug configuration":"選取偵錯設定","Select the process to attach to":"選取要附加至的目標處理序","Show as Hex":"顯示為十六進位","The minimum supported Python version for the debugger extension is 3.9.":"偵測工具擴充功能的最低支援 Python 版本為 3.9。","We noticed you are attaching to ptvsd (Python debugger), which was deprecated on May 1st, 2020. Please switch to [debugpy](https://aka.ms/migrateToDebugpy).":"我們注意到您正在附加到 ptvsd (Python 偵錯工具),已於 2020 年 5 月 1 日淘汰。請切換到 [debugpy](https://aka.ms/migrateToDebugpy).","You need to select a Python interpreter before you start debugging.\n\nTip: click on \"Select Interpreter\" in the status bar.":"您必須先選取 Python 解譯器,才能開始偵錯。\n\n提示: 按一下狀態列中的 [選取解譯器]。","cwd:":"cwd:","enter-your-module-name":"enter-your-module-name"} diff --git a/src/extension/common/application/commands/reportIssueCommand.ts b/src/extension/common/application/commands/reportIssueCommand.ts index 104b5225..7cdd88df 100644 --- a/src/extension/common/application/commands/reportIssueCommand.ts +++ b/src/extension/common/application/commands/reportIssueCommand.ts @@ -6,29 +6,39 @@ import * as fs from 'fs-extra'; import * as path from 'path'; import { executeCommand } from '../../vscodeapi'; -import { getActiveEnvironmentPath, resolveEnvironment } from '../../python'; import { EXTENSION_ROOT_DIR } from '../../constants'; -import { getRawVersion } from '../../settings'; import { sendTelemetryEvent } from '../../../telemetry'; import { EventName } from '../../../telemetry/constants'; +import { PythonEnvironment } from '../../../envExtApi'; +import { traceLog } from '../../log/logging'; +import { getActiveEnvironmentPath, resolveEnvironment } from '../../python'; /** * Allows the user to report an issue related to the Python Debugger extension using our template. */ export async function openReportIssue(): Promise { + traceLog('openReportIssue: Starting report issue flow'); const templatePath = path.join(EXTENSION_ROOT_DIR, 'resources', 'report_issue_template.md'); const userDataTemplatePath = path.join(EXTENSION_ROOT_DIR, 'resources', 'report_issue_user_data_template.md'); const template = await fs.readFile(templatePath, 'utf8'); const userTemplate = await fs.readFile(userDataTemplatePath, 'utf8'); + // get active environment and resolve it const interpreterPath = await getActiveEnvironmentPath(); - const interpreter = await resolveEnvironment(interpreterPath); - const virtualEnvKind = interpreter?.environment?.type || 'Unknown'; + let interpreter: PythonEnvironment | undefined = undefined; + if (interpreterPath && 'environmentPath' in interpreterPath) { + interpreter = await resolveEnvironment(interpreterPath.environmentPath.fsPath); + } else if (interpreterPath && 'path' in interpreterPath) { + interpreter = await resolveEnvironment(interpreterPath.path); + } + const virtualEnvKind = interpreter && interpreter.envId ? interpreter.envId.managerId : 'Unknown'; + const pythonVersion = interpreter?.version ?? 'unknown'; + traceLog(`openReportIssue: Resolved pythonVersion='${pythonVersion}' envKind='${virtualEnvKind}'`); - const pythonVersion = getRawVersion(interpreter?.version); await executeCommand('workbench.action.openIssueReporter', { extensionId: 'ms-python.debugpy', issueBody: template, data: userTemplate.replace('{0}', pythonVersion).replace('{1}', virtualEnvKind), }); sendTelemetryEvent(EventName.USE_REPORT_ISSUE_COMMAND, undefined, {}); + traceLog('openReportIssue: Issue reporter command executed'); } diff --git a/src/extension/common/legacyPython.ts b/src/extension/common/legacyPython.ts new file mode 100644 index 00000000..f8d01526 --- /dev/null +++ b/src/extension/common/legacyPython.ts @@ -0,0 +1,240 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +/* eslint-disable @typescript-eslint/naming-convention */ +import { + ActiveEnvironmentPathChangeEvent, + Environment, + EnvironmentPath, + EnvironmentVariables, + PythonExtension, + ResolvedEnvironment, + Resource, +} from '@vscode/python-extension'; +import { EventEmitter, extensions, Uri, Disposable, Extension } from 'vscode'; +import { createDeferred } from './utils/async'; +import { traceError, traceLog } from './log/logging'; + +/** + * Interface for the Python extension API. + */ +interface LegacyIExtensionApi { + ready: Promise; + settings: { + getExecutionDetails(resource?: Resource): { execCommand: string[] | undefined }; + }; +} + +/** + * Details about a Python interpreter. + */ +export interface LegacyIInterpreterDetails { + /** Array of path components to the Python executable */ + path?: string[]; + /** The workspace resource associated with this interpreter */ + resource?: Uri; +} + +// /** Event emitter for Python interpreter changes */ +// const legacyOnDidChangePythonInterpreterEvent = new EventEmitter(); + +// /** Event that fires when the active Python interpreter changes */ +// export const legacyOnDidChangePythonInterpreter: Event = +// legacyOnDidChangePythonInterpreterEvent.event; +/** + * Activates the Python extension and ensures it's ready for use. + * @returns The activated Python extension instance + */ +async function legacyActivateExtension(): Promise | undefined> { + console.log('Activating Python extension...'); + activateEnvsExtension(); + const extension = extensions.getExtension('ms-python.python'); + if (extension) { + if (!extension.isActive) { + await extension.activate(); + } + } + console.log('Python extension activated.'); + return extension; +} +/** + * Activates the Python environments extension. + * @returns The activated Python environments extension instance + */ +async function activateEnvsExtension(): Promise | undefined> { + const extension = extensions.getExtension('ms-python.vscode-python-envs'); + if (extension) { + if (!extension.isActive) { + await extension.activate(); + } + } + return extension; +} + +/** + * Gets the Python extension's API interface. + * @returns The Python extension API or undefined if not available + */ +async function legacyGetPythonExtensionAPI(): Promise { + const extension = await legacyActivateExtension(); + return extension?.exports as LegacyIExtensionApi; +} + +/** + * Gets the Python extension's environment API. + * @returns The Python extension environment API + */ +async function legacyGetPythonExtensionEnviromentAPI(): Promise { + // Load the Python extension API + await legacyActivateExtension(); + return await PythonExtension.api(); +} + +/** + * Initializes Python integration by setting up event listeners and getting initial interpreter details. + * @param disposables Array to store disposable resources for cleanup + */ +export async function legacyInitializePython( + disposables: Disposable[], + onDidChangePythonInterpreterEvent: EventEmitter, +): Promise { + try { + traceLog('legacyInitializePython: Starting initialization'); + const api = await legacyGetPythonExtensionEnviromentAPI(); + + if (api) { + disposables.push( + // This event is triggered when the active environment setting changes. + api.environments.onDidChangeActiveEnvironmentPath((e: ActiveEnvironmentPathChangeEvent) => { + traceLog(`legacyInitializePython: Active environment path changed to '${e.path}'`); + let resourceUri: Uri | undefined; + if (e.resource instanceof Uri) { + resourceUri = e.resource; + } + if (e.resource && 'uri' in e.resource) { + // WorkspaceFolder type + resourceUri = e.resource.uri; + } + onDidChangePythonInterpreterEvent.fire({ path: [e.path], resource: resourceUri }); + }), + ); + + traceLog('Waiting for interpreter from python extension.'); + onDidChangePythonInterpreterEvent.fire(await legacyGetInterpreterDetails()); + traceLog('legacyInitializePython: Initial interpreter details fired'); + } + } catch (error) { + traceError('Error initializing python: ', error); + } +} + +/** + * Returns all the details needed to execute code within the selected environment, + * corresponding to the specified resource taking into account any workspace-specific settings + * for the workspace to which this resource belongs. + * @param resource Optional workspace resource to get settings for + * @returns Array of command components or undefined if not available + */ +export async function legacyGetSettingsPythonPath(resource?: Uri): Promise { + const api = await legacyGetPythonExtensionAPI(); + const execCommand = api?.settings.getExecutionDetails(resource).execCommand; + traceLog(`legacyGetSettingsPythonPath: execCommand='${execCommand?.join(' ')}' resource='${resource?.fsPath}'`); + return execCommand; +} + +/** + * Returns the environment variables used by the extension for a resource, which includes the custom + * variables configured by user in `.env` files. + * @param resource Optional workspace resource to get environment variables for + * @returns Environment variables object + */ +export async function legacyGetEnvironmentVariables(resource?: Resource): Promise { + const api = await legacyGetPythonExtensionEnviromentAPI(); + return Promise.resolve(api.environments.getEnvironmentVariables(resource)); +} + +/** + * Returns details for the given environment, or `undefined` if the env is invalid. + * @param env Environment to resolve (can be Environment object, path, or string) + * @returns Resolved environment details + */ +export async function legacyResolveEnvironment( + env: Environment | EnvironmentPath | string, +): Promise { + const api = await legacyGetPythonExtensionEnviromentAPI(); + traceLog(`legacyResolveEnvironment: Resolving environment '${typeof env === 'string' ? env : (env as any).path}'`); + const resolved = api.environments.resolveEnvironment(env); + resolved.then((r) => traceLog(`legacyResolveEnvironment: Resolved executable='${r?.executable.uri?.fsPath}'`)); + return resolved; +} + +/** + * Returns the environment configured by user in settings. Note that this can be an invalid environment, use + * resolve the environment to get full details. + * @param resource Optional workspace resource to get active environment for + * @returns Path to the active environment + */ +export async function legacyGetActiveEnvironmentPath(resource?: Resource): Promise { + const api = await legacyGetPythonExtensionEnviromentAPI(); + const active = api.environments.getActiveEnvironmentPath(resource); + traceLog( + `legacyGetActiveEnvironmentPath: activePath='${active.path}' resource='${ + (resource as any)?.uri?.fsPath || (resource as Uri)?.fsPath || '' + }'`, + ); + return active; +} + +/** + * Gets detailed information about the active Python interpreter. + * @param resource Optional workspace resource to get interpreter details for + * @returns Interpreter details including path and resource information + */ +export async function legacyGetInterpreterDetails(resource?: Uri): Promise { + const api = await legacyGetPythonExtensionEnviromentAPI(); + const environment = await api.environments.resolveEnvironment(api.environments.getActiveEnvironmentPath(resource)); + if (environment?.executable.uri) { + traceLog( + `legacyGetInterpreterDetails: executable='${environment.executable.uri.fsPath}' resource='${resource?.fsPath}'`, + ); + return { path: [environment?.executable.uri.fsPath], resource }; + } + traceLog('legacyGetInterpreterDetails: No executable found'); + return { path: undefined, resource }; +} + +/** + * Checks if any Python interpreters are available in the system. + * @returns True if interpreters are found, false otherwise + */ +export async function legacyHasInterpreters(): Promise { + const api = await legacyGetPythonExtensionEnviromentAPI(); + const onAddedToCollection = createDeferred(); + api.environments.onDidChangeEnvironments(async () => { + if (api.environments.known) { + onAddedToCollection.resolve(); + } + }); + const initialEnvs = api.environments.known; + if (initialEnvs.length > 0) { + traceLog(`legacyHasInterpreters: Found ${initialEnvs.length} initial environments`); + return true; + } + // Initiates a refresh of Python environments within the specified scope. + await Promise.race([onAddedToCollection.promise, api?.environments.refreshEnvironments()]); + const has = api.environments.known.length > 0; + traceLog(`legacyHasInterpreters: After refresh count='${api.environments.known.length}' result='${has}'`); + return has; +} + +/** + * Gets environments known to the extension at the time of fetching the property. Note this may not + * contain all environments in the system as a refresh might be going on. + * @returns Array of known Python environments + */ +export async function legacyGetInterpreters(): Promise { + const api = await legacyGetPythonExtensionEnviromentAPI(); + const known = api.environments.known || []; + traceLog(`legacyGetInterpreters: returning ${known.length} environments`); + return known; +} diff --git a/src/extension/common/onErrorsAction.ts b/src/extension/common/onErrorsAction.ts new file mode 100644 index 00000000..bf2651a7 --- /dev/null +++ b/src/extension/common/onErrorsAction.ts @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import { DiagnosticSeverity, l10n, languages, MessageOptions, window } from 'vscode'; +import { getConfiguration } from './vscodeapi'; + +export async function resolveOnErrorsAction(): Promise { + const onErrors = getConfiguration('debugpy').get('onErrors', OnErrorsActions.debugAnyway); + if (onErrors === OnErrorsActions.debugAnyway) { + return OnErrorsActions.debugAnyway; + } + + const hasErrors = languages + .getDiagnostics() + .map((d) => { + return d[1]; + }) + .flat() + .some((d) => { + return d.severity === DiagnosticSeverity.Error; + }); + if (!hasErrors) { + return OnErrorsActions.debugAnyway; + } + + if (onErrors === OnErrorsActions.prompt) { + const message = l10n.t('Error exists before debugging.'); + const options: MessageOptions = { modal: true }; + const actions = [ + { title: 'Debug Anyway', id: OnErrorsActions.debugAnyway }, + { title: 'Show Errors', id: OnErrorsActions.showErrors }, + { title: 'Abort', id: OnErrorsActions.abort, isCloseAffordance: true }, + ]; + + const result = await window.showWarningMessage(message, options, ...actions); + return (result?.id as OnErrorsActions) ?? OnErrorsActions.abort; + } + + return onErrors as OnErrorsActions; +} + +export enum OnErrorsActions { + debugAnyway = 'debugAnyway', + showErrors = 'showErrors', + abort = 'abort', + prompt = 'prompt', +} diff --git a/src/extension/common/python.ts b/src/extension/common/python.ts index a82fb559..2fadbf18 100644 --- a/src/extension/common/python.ts +++ b/src/extension/common/python.ts @@ -2,117 +2,268 @@ // Licensed under the MIT License. /* eslint-disable @typescript-eslint/naming-convention */ -import { Environment, EnvironmentPath, PythonExtension, Resource } from '@vscode/python-extension'; -import { commands, EventEmitter, extensions, Uri, Event, Disposable } from 'vscode'; -import { createDeferred } from './utils/async'; +import { Environment, EnvironmentPath, ResolvedEnvironment, Resource } from '@vscode/python-extension'; +import { commands, EventEmitter, extensions, Uri, Event, Disposable, Extension } from 'vscode'; import { traceError, traceLog } from './log/logging'; - -interface IExtensionApi { - ready: Promise; - settings: { - getExecutionDetails(resource?: Resource): { execCommand: string[] | undefined }; - }; -} +import { PythonEnvironment, PythonEnvironmentApi, PythonEnvsExtension } from '../envExtApi'; +import { + legacyGetActiveEnvironmentPath, + legacyGetEnvironmentVariables, + legacyGetInterpreterDetails, + legacyGetSettingsPythonPath, + legacyInitializePython, + legacyResolveEnvironment, +} from './legacyPython'; +import { useEnvExtension } from './utilities'; +import { EnvironmentVariables } from './variables/types'; export interface IInterpreterDetails { path?: string[]; resource?: Uri; } +/** Event emitter for Python interpreter changes */ const onDidChangePythonInterpreterEvent = new EventEmitter(); + export const onDidChangePythonInterpreter: Event = onDidChangePythonInterpreterEvent.event; -async function activateExtension() { + +async function activateExtensions() { + traceLog('Value during activateExtensions of useEnvExtension(): ', useEnvExtension()); + await activatePythonExtension(); + await activateEnvsExtension(); +} + +async function activatePythonExtension() { const extension = extensions.getExtension('ms-python.python'); if (extension) { if (!extension.isActive) { + console.log('Activating Python extension...'); await extension.activate(); } } return extension; } - -async function getPythonExtensionAPI(): Promise { - const extension = await activateExtension(); - return extension?.exports as IExtensionApi; +/** + * Activates the Python environments extension. + * @returns The activated Python environments extension instance + */ +async function activateEnvsExtension(): Promise | undefined> { + const extension = extensions.getExtension('ms-python.vscode-python-envs'); + if (extension) { + if (!extension.isActive) { + console.log('Activating Python Environments extension...'); + await extension.activate(); + } + } + return extension; } -async function getPythonExtensionEnviromentAPI(): Promise { - // Load the Python extension API - await activateExtension(); - return await PythonExtension.api(); +export async function getPythonEnvironmentExtensionAPI(): Promise { + await activateEnvsExtension(); + return await PythonEnvsExtension.api(); } export async function initializePython(disposables: Disposable[]): Promise { - try { - const api = await getPythonExtensionEnviromentAPI(); - - if (api) { - disposables.push( - api.environments.onDidChangeActiveEnvironmentPath((e) => { - onDidChangePythonInterpreterEvent.fire({ path: [e.path], resource: e.resource?.uri }); - }), - ); + traceLog(`initializePython: usingEnvExt='${useEnvExtension()}'`); + if (!useEnvExtension()) { + await legacyInitializePython(disposables, onDidChangePythonInterpreterEvent); + } else { + try { + const api = await getPythonEnvironmentExtensionAPI(); + if (api) { + disposables.push( + api.onDidChangeEnvironments(async () => { + const details = await getInterpreterDetails(); + traceLog(`initializePython:onDidChangeEnvironments fired executable='${details.path?.[0]}'`); + onDidChangePythonInterpreterEvent.fire(details); + traceLog('Python environments changed event processed.'); + }), + ); - traceLog('Waiting for interpreter from python extension.'); - onDidChangePythonInterpreterEvent.fire(await getInterpreterDetails()); + traceLog('Waiting for interpreter from python environments extension.'); + onDidChangePythonInterpreterEvent.fire(await getInterpreterDetails()); + traceLog('initializePython: Initial interpreter details fired (env extension path)'); + } + } catch (error) { + traceError('Error initializing python: ', error); } - } catch (error) { - traceError('Error initializing python: ', error); } } export async function runPythonExtensionCommand(command: string, ...rest: any[]) { - await activateExtension(); + await activateExtensions(); + traceLog(`runPythonExtensionCommand: executing command='${command}' argsCount='${rest.length}'`); return await commands.executeCommand(command, ...rest); } +/** + * Returns all the details needed to execute code within the selected environment, + * corresponding to the specified resource taking into account any workspace-specific settings + * for the workspace to which this resource belongs. + * @param resource Optional workspace resource to get settings for + * @returns Array of command components or undefined if not available + */ export async function getSettingsPythonPath(resource?: Uri): Promise { - const api = await getPythonExtensionAPI(); - return api?.settings.getExecutionDetails(resource).execCommand; -} + // this one is only called if getInterpreterDetails(workspaceFolder) doesn't return somethinig with r.path + if (!useEnvExtension()) { + return legacyGetSettingsPythonPath(resource); + } else { + const api = await getPythonEnvironmentExtensionAPI(); + let pyEnv = await api.getEnvironment(resource); -export async function getEnvironmentVariables(resource?: Resource) { - const api = await getPythonExtensionEnviromentAPI(); - return api.environments.getEnvironmentVariables(resource); -} + if (!pyEnv) { + traceLog(`getSettingsPythonPath: No environment for resource='${resource?.fsPath}'`); + return undefined; + } -export async function resolveEnvironment(env: Environment | EnvironmentPath | string) { - const api = await getPythonExtensionEnviromentAPI(); - return api.environments.resolveEnvironment(env); -} + // Resolve environment if execution info is not available + if (!pyEnv.execInfo) { + pyEnv = await api.resolveEnvironment(pyEnv.environmentPath); + traceLog( + `getSettingsPythonPath: Resolved environment execInfo for '${ + pyEnv?.environmentPath.fsPath || 'undefined' + }'`, + ); + } -export async function getActiveEnvironmentPath(resource?: Resource) { - const api = await getPythonExtensionEnviromentAPI(); - return api.environments.getActiveEnvironmentPath(resource); -} + // Extract execution command from resolved environment + const execInfo = pyEnv?.execInfo; + if (!execInfo) { + traceLog('getSettingsPythonPath: Missing execInfo after resolution'); + return undefined; + } -export async function getInterpreterDetails(resource?: Uri): Promise { - const api = await getPythonExtensionEnviromentAPI(); - const environment = await api.environments.resolveEnvironment(api.environments.getActiveEnvironmentPath(resource)); - if (environment?.executable.uri) { - return { path: [environment?.executable.uri.fsPath], resource }; + const runConfig = execInfo.activatedRun ?? execInfo.run; + traceLog( + `getSettingsPythonPath: Using executable='${runConfig.executable}' args='${ + runConfig.args?.join(' ') || '' + }'`, + ); + return runConfig.args ? [runConfig.executable, ...runConfig.args] : [runConfig.executable]; + } +} // should I make this more async? rn it just becomes sync + +export async function getEnvironmentVariables(resource?: Resource): Promise { + if (!useEnvExtension()) { + return legacyGetEnvironmentVariables(resource); + } else { + const api = await getPythonEnvironmentExtensionAPI(); + + // Convert resource to Uri or undefined + const resourceUri = + resource instanceof Uri ? resource : resource && 'uri' in resource ? resource.uri : undefined; + + return api.getEnvironmentVariables(resourceUri); } - return { path: undefined, resource }; } -export async function hasInterpreters() { - const api = await getPythonExtensionEnviromentAPI(); - const onAddedToCollection = createDeferred(); - api.environments.onDidChangeEnvironments(async () => { - if (api.environments.known) { - onAddedToCollection.resolve(); +export async function resolveEnvironment( + env: Environment | EnvironmentPath | string, +): Promise { + if (!useEnvExtension()) { + const legacyResolvedEnv: ResolvedEnvironment | undefined = await legacyResolveEnvironment(env); + // if its a legacy path, convert to new python environment + const pythonVersion = legacyResolvedEnv?.version + ? `${legacyResolvedEnv.version.major}.${legacyResolvedEnv.version.minor}.${legacyResolvedEnv.version.micro}` + : 'Unknown'; + const execUri = legacyResolvedEnv?.executable.uri; + if (execUri === undefined) { + traceLog('resolveEnvironment: legacy path invalid (no executable uri)'); + // Should return undefined for invalid environment + return undefined; + } + if (legacyResolvedEnv) { + traceLog(`resolveEnvironment: legacy resolved executable='${execUri.fsPath}' version='${pythonVersion}'`); + const pythonEnv: PythonEnvironment = { + envId: { + id: execUri.fsPath, + managerId: legacyResolvedEnv.environment?.type ?? 'Venv', + }, + name: legacyResolvedEnv.environment?.name ?? `Python ${pythonVersion ?? 'Unknown'}`, + displayName: legacyResolvedEnv.environment?.name ?? `Python ${pythonVersion ?? 'Unknown'}`, + displayPath: execUri.fsPath, + version: pythonVersion, + environmentPath: execUri, + execInfo: { + run: { + executable: execUri.fsPath, + args: [], + }, + }, + sysPrefix: legacyResolvedEnv.executable.sysPrefix ?? '', + }; + return pythonEnv; + } + } else { + const api = await getPythonEnvironmentExtensionAPI(); + + // Handle different input types for the new API + if (typeof env === 'string') { + // Convert string path to Uri for the new API + traceLog(`resolveEnvironment: new API resolving from string='${env}'`); + return api.resolveEnvironment(Uri.file(env)); + } else if (typeof env === 'object' && 'path' in env) { + // EnvironmentPath has a uri property + traceLog(`resolveEnvironment: new API resolving from EnvironmentPath='${env.path}'`); + return api.resolveEnvironment(Uri.file(env.path)); + } else { + traceLog('resolveEnvironment: new API unsupported env input'); + return undefined; } - }); - const initialEnvs = api.environments.known; - if (initialEnvs.length > 0) { - return true; } - await Promise.race([onAddedToCollection.promise, api?.environments.refreshEnvironments()]); +} + +export async function getActiveEnvironmentPath( + resource?: Resource, +): Promise { + if (!useEnvExtension()) { + const envPath: EnvironmentPath = await legacyGetActiveEnvironmentPath(resource); + traceLog(`getActiveEnvironmentPath: legacy active path='${envPath.path}'`); + return envPath; + } else { + const api = await getPythonEnvironmentExtensionAPI(); - return api.environments.known.length > 0; + // Convert resource to Uri | undefined from Resource | undefined + const resourceUri = + resource instanceof Uri ? resource : resource && 'uri' in resource ? resource.uri : undefined; + + const env = await api.getEnvironment(resourceUri); + traceLog( + `getActiveEnvironmentPath: new API envPath='${env?.environmentPath.fsPath}' resource='${resourceUri?.fsPath}'`, + ); + return env; + } } -export async function getInterpreters() { - const api = await getPythonExtensionEnviromentAPI(); - return api.environments.known || []; +/** + * Gets Python interpreter details using the Python Envs extension API. + * + * This function retrieves the active Python environment for a given resource using the + * legacy @vscode/python-extension API. It resolves the environment to get the executable + * path and handles path quoting for paths containing spaces. + * + * @param resource Optional URI to specify the workspace/folder context for interpreter selection + * @returns Promise resolving to interpreter details containing the executable path and resource + */ +export async function getInterpreterDetails(resource?: Uri): Promise { + if (!useEnvExtension()) { + return legacyGetInterpreterDetails(resource); + } else { + const api = await getPythonEnvironmentExtensionAPI(); + + // A promise that resolves to the current Python environment, or undefined if none is set. + const env: PythonEnvironment | undefined = await api.getEnvironment(resource); + // resolve the environment to get full details + const resolvedEnv = env ? await api.resolveEnvironment(env?.environmentPath) : undefined; + const executablePath = resolvedEnv?.execInfo.activatedRun?.executable + ? resolvedEnv.execInfo.activatedRun.executable + : resolvedEnv?.execInfo.run.executable; + + const a: IInterpreterDetails = { + path: executablePath ? [executablePath] : undefined, + resource, + }; + traceLog(`getInterpreterDetails: resource='${resource?.fsPath}' executable='${executablePath}'`); + return a; + } } diff --git a/src/extension/common/settings.ts b/src/extension/common/settings.ts index 9239a4f8..d4db2567 100644 --- a/src/extension/common/settings.ts +++ b/src/extension/common/settings.ts @@ -2,10 +2,10 @@ // Licensed under the MIT License. import { ConfigurationChangeEvent, ConfigurationTarget, Uri, WorkspaceConfiguration, WorkspaceFolder } from 'vscode'; -import { getInterpreterDetails } from './python'; import { getConfiguration, getWorkspaceFolder, getWorkspaceFolders } from './vscodeapi'; import { isUnitTestExecution } from './constants'; import { VersionInfo } from '@vscode/python-extension'; +import { getInterpreterDetails } from './python'; export interface ISettings { workspace: string; diff --git a/src/extension/common/utilities.ts b/src/extension/common/utilities.ts index c58f5a08..675d5fe7 100644 --- a/src/extension/common/utilities.ts +++ b/src/extension/common/utilities.ts @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import { Extension, extensions } from 'vscode'; +import { getConfiguration } from './vscodeapi'; + /** * Returns the elements of an array that meet the condition specified in an async callback function. * @param asyncPredicate The filter method calls the async predicate function one time for each element in the array. @@ -9,3 +12,20 @@ export async function asyncFilter(arr: T[], asyncPredicate: (value: T) => Pro const results = await Promise.all(arr.map(asyncPredicate)); return arr.filter((_v, index) => results[index]); } + +export function getExtension(extensionId: string): Extension | undefined { + return extensions.getExtension(extensionId); +} +let _useExt: boolean | undefined; +export const ENVS_EXTENSION_ID = 'ms-python.vscode-python-envs'; + +export function useEnvExtension(): boolean { + if (_useExt !== undefined) { + return _useExt; + } + const inExpSetting = getConfiguration('python').get('useEnvironmentsExtension', false); + + // If extension is installed and in experiment, then use it. + _useExt = !!getExtension(ENVS_EXTENSION_ID) && inExpSetting; + return _useExt; +} diff --git a/src/extension/debugger/adapter/factory.ts b/src/extension/debugger/adapter/factory.ts index c5242c17..5666cd0a 100644 --- a/src/extension/debugger/adapter/factory.ts +++ b/src/extension/debugger/adapter/factory.ts @@ -19,12 +19,12 @@ import { executeCommand, showErrorMessage } from '../../common/vscodeapi'; import { traceLog, traceVerbose } from '../../common/log/logging'; import { EventName } from '../../telemetry/constants'; import { sendTelemetryEvent } from '../../telemetry'; -import { getInterpreterDetails, resolveEnvironment, runPythonExtensionCommand } from '../../common/python'; import { Commands, EXTENSION_ROOT_DIR } from '../../common/constants'; import { Common, DebugConfigStrings, Interpreters } from '../../common/utils/localize'; import { IPersistentStateFactory } from '../../common/types'; -import { ResolvedEnvironment } from '@vscode/python-extension'; import { fileToCommandArgumentForPythonExt } from '../../common/stringUtils'; +import { PythonEnvironment } from '../../envExtApi'; +import { resolveEnvironment, getInterpreterDetails, runPythonExtensionCommand } from '../../common/python'; // persistent state names, exported to make use of in testing export enum debugStateKeys { @@ -38,6 +38,7 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac session: DebugSession, _executable: DebugAdapterExecutable | undefined, ): Promise { + traceLog(`createDebugAdapterDescriptor: request='${session.configuration.request}' name='${session.name}'`); const configuration = session.configuration as LaunchRequestArguments | AttachRequestArguments; // There are four distinct scenarios here: @@ -67,9 +68,11 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac } else if (configuration.listen === undefined && configuration.processId === undefined) { throw new Error('"request":"attach" requires either "connect", "listen", or "processId"'); } + traceLog('createDebugAdapterDescriptor: attach scenario using spawned adapter'); } const command = await this.getDebugAdapterPython(configuration, session.workspaceFolder); + traceLog(`createDebugAdapterDescriptor: python command parts='${command.join(' ')}'`); if (command.length !== 0) { if (configuration.request === 'attach' && configuration.processId !== undefined) { sendTelemetryEvent(EventName.DEBUGGER_ATTACH_TO_LOCAL_PROCESS); @@ -114,6 +117,7 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac configuration: LaunchRequestArguments | AttachRequestArguments, workspaceFolder?: WorkspaceFolder, ): Promise { + traceVerbose('getDebugAdapterPython: Resolving interpreter for debug adapter'); if (configuration.debugAdapterPython !== undefined) { return this.getExecutableCommand(await resolveEnvironment(configuration.debugAdapterPython)); } else if (configuration.pythonPath) { @@ -159,7 +163,7 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac } const prompts = [Interpreters.changePythonInterpreter, Common.doNotShowAgain]; const selection = await showErrorMessage( - l10n.t('The debugger in the python extension no longer supports python versions minor than 3.9.'), + l10n.t('The minimum supported Python version for the debugger extension is 3.9.'), { modal: true }, ...prompts, ); @@ -177,15 +181,33 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac } } - private async getExecutableCommand(interpreter: ResolvedEnvironment | undefined): Promise { + /** + * Extracts the executable command from a resolved Python environment. + * + * This function takes a resolved Python environment and returns the path to the Python + * executable as a string array suitable for spawning processes. It also performs version + * validation, showing a deprecation warning if the Python version is below 3.9. + * + * @param interpreter The resolved Python environment containing executable path and version info + * @returns Promise resolving to an array containing the Python executable path, or empty array if no interpreter + */ + private async getExecutableCommand(interpreter: PythonEnvironment | undefined): Promise { if (interpreter) { - if ( - (interpreter.version?.major ?? 0) < 3 || - ((interpreter.version?.major ?? 0) <= 3 && (interpreter.version?.minor ?? 0) <= 9) - ) { + const executablePath = interpreter.execInfo.activatedRun?.executable ?? interpreter.execInfo.run.executable; + const version = interpreter.version; + + // Parse version string (e.g., "3.8.10" -> major: 3, minor: 8) + const parseMajorMinor = (v: string) => { + const m = v.match(/^(\d+)(?:\.(\d+))?/); + return { major: m && m[1] ? Number(m[1]) : 0, minor: m && m[2] ? Number(m[2]) : 0 }; + }; + const { major, minor } = parseMajorMinor(version || ''); + + if (major < 3 || (major <= 3 && minor < 9)) { this.showDeprecatedPythonMessage(); } - return interpreter.path.length > 0 ? [interpreter.path] : []; + traceLog(`getExecutableCommand: executable='${executablePath}' version='${version}'`); + return executablePath ? [executablePath] : []; } return []; } diff --git a/src/extension/debugger/configuration/debugConfigurationService.ts b/src/extension/debugger/configuration/debugConfigurationService.ts index 8776f9b6..3ae3e2e4 100644 --- a/src/extension/debugger/configuration/debugConfigurationService.ts +++ b/src/extension/debugger/configuration/debugConfigurationService.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +import * as fs from 'fs'; import { cloneDeep } from 'lodash'; -import { CancellationToken, DebugConfiguration, QuickPickItem, WorkspaceFolder } from 'vscode'; +import { CancellationToken, commands, DebugConfiguration, QuickPickItem, Uri, WorkspaceFolder } from 'vscode'; import { DebugConfigStrings } from '../../common/utils/localize'; import { IMultiStepInputFactory, InputStep, IQuickPickParameters, MultiStepInput } from '../../common/multiStepInput'; import { AttachRequestArguments, DebugConfigurationArguments, LaunchRequestArguments } from '../../types'; @@ -17,6 +18,9 @@ import { buildPyramidLaunchConfiguration } from './providers/pyramidLaunch'; import { buildRemoteAttachConfiguration } from './providers/remoteAttach'; import { IDebugConfigurationResolver } from './types'; import { buildFileWithArgsLaunchDebugConfiguration } from './providers/fileLaunchWithArgs'; +import { getInterpreterDetails } from '../../common/python'; +import { traceLog } from '../../common/log/logging'; +import { OnErrorsActions, resolveOnErrorsAction } from '../../common/onErrorsAction'; export class PythonDebugConfigurationService implements IDebugConfigurationService { private cacheDebugConfig: DebugConfiguration | undefined = undefined; @@ -48,6 +52,15 @@ export class PythonDebugConfigurationService implements IDebugConfigurationServi debugConfiguration: DebugConfiguration, token?: CancellationToken, ): Promise { + const action = await resolveOnErrorsAction(); + switch (action) { + case OnErrorsActions.showErrors: + await commands.executeCommand('workbench.panel.markers.view.focus'); + return undefined; + + case OnErrorsActions.abort: + return undefined; + } if (debugConfiguration.request === 'attach') { return this.attachResolver.resolveDebugConfiguration( folder, @@ -90,6 +103,24 @@ export class PythonDebugConfigurationService implements IDebugConfigurationServi debugConfiguration: DebugConfiguration, token?: CancellationToken, ): Promise { + // now that ${file} is resolved, we can use it to get the interpreter for that file + if (debugConfiguration.program !== undefined) { + if (debugConfiguration.python === undefined) { + // If program is a valid file, get interpreter for that file + if (fs.existsSync(debugConfiguration.program) && fs.statSync(debugConfiguration.program).isFile()) { + traceLog( + `resolveDebugConfigurationWithSubstitutedVariables: resolving interpreter for program='${debugConfiguration.program}'`, + ); + const interpreter = await getInterpreterDetails(Uri.file(debugConfiguration.program)); + if (interpreter?.path && interpreter.path.length > 0) { + traceLog( + `resolveDebugConfigurationWithSubstitutedVariables: setting debugConfiguration.python='${interpreter.path[0]}'`, + ); + debugConfiguration.python = interpreter.path[0]; + } + } + } + } function resolve(resolver: IDebugConfigurationResolver) { return resolver.resolveDebugConfigurationWithSubstitutedVariables(folder, debugConfiguration as T, token); } diff --git a/src/extension/debugger/configuration/providers/pyramidLaunch.ts b/src/extension/debugger/configuration/providers/pyramidLaunch.ts index 47476be9..39aee600 100644 --- a/src/extension/debugger/configuration/providers/pyramidLaunch.ts +++ b/src/extension/debugger/configuration/providers/pyramidLaunch.ts @@ -13,7 +13,7 @@ import { EventName } from '../../../telemetry/constants'; import { DebuggerTypeName } from '../../../constants'; import { LaunchRequestArguments } from '../../../types'; import { DebugConfigurationState, DebugConfigurationType } from '../../types'; -import { resolveVariables } from '../utils/common'; +import { resolveWorkspaceVariables } from '../utils/common'; const workspaceFolderToken = '${workspaceFolder}'; @@ -73,7 +73,7 @@ export async function validateIniPath( if (!selected || selected.trim().length === 0) { return error; } - const resolvedPath = resolveVariables(selected, undefined, folder); + const resolvedPath = resolveWorkspaceVariables(selected, undefined, folder); if (resolvedPath) { if (selected !== defaultValue && !fs.pathExists(resolvedPath)) { return error; diff --git a/src/extension/debugger/configuration/resolvers/base.ts b/src/extension/debugger/configuration/resolvers/base.ts index 68025da8..8dc477a6 100644 --- a/src/extension/debugger/configuration/resolvers/base.ts +++ b/src/extension/debugger/configuration/resolvers/base.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. 'use strict'; - +import * as fs from 'fs'; import * as path from 'path'; import { CancellationToken, DebugConfiguration, Uri, WorkspaceFolder } from 'vscode'; import { sendTelemetryEvent } from '../../../telemetry'; @@ -12,7 +12,7 @@ import { getWorkspaceFolders, getWorkspaceFolder as getVSCodeWorkspaceFolder } f import { AttachRequestArguments, DebugOptions, LaunchRequestArguments, PathMapping } from '../../../types'; import { PythonPathSource } from '../../types'; import { IDebugConfigurationResolver } from '../types'; -import { resolveVariables } from '../utils/common'; +import { resolveWorkspaceVariables } from '../utils/common'; import { getProgram } from './helper'; import { getSettingsPythonPath, getInterpreterDetails } from '../../../common/python'; import { getOSType, OSType } from '../../../common/platform'; @@ -80,6 +80,16 @@ export abstract class BaseConfigurationResolver return undefined; } + /** + * Resolves and updates file paths and Python interpreter paths in the debug configuration. + * + * This method performs two main operations: + * 1. Resolves workspace variables in the envFile path (if specified) + * 2. Resolves and updates Python interpreter paths, handling legacy pythonPath deprecation + * + * @param workspaceFolder The workspace folder URI for variable resolution + * @param debugConfiguration The launch configuration to update + */ protected async resolveAndUpdatePaths( workspaceFolder: Uri | undefined, debugConfiguration: LaunchRequestArguments, @@ -88,22 +98,38 @@ export abstract class BaseConfigurationResolver await this.resolveAndUpdatePythonPath(workspaceFolder, debugConfiguration); } + /** + * Resolves workspace variables in the envFile path. + * + * Expands variables like ${workspaceFolder} in the envFile configuration using the + * workspace folder path or current working directory as the base for resolution. + * + * @param workspaceFolder The workspace folder URI for variable resolution + * @param debugConfiguration The launch configuration containing the envFile path + */ protected static resolveAndUpdateEnvFilePath( workspaceFolder: Uri | undefined, debugConfiguration: LaunchRequestArguments, ): void { - if (!debugConfiguration) { + // Early exit if no configuration or no envFile to resolve + if (!debugConfiguration?.envFile) { return; } - if (debugConfiguration.envFile && (workspaceFolder || debugConfiguration.cwd)) { - debugConfiguration.envFile = resolveVariables( - debugConfiguration.envFile, - (workspaceFolder ? workspaceFolder.fsPath : undefined) || debugConfiguration.cwd, - undefined, - ); + + const basePath = workspaceFolder?.fsPath || debugConfiguration.cwd; + + if (basePath) { + // update envFile with resolved variables + debugConfiguration.envFile = resolveWorkspaceVariables(debugConfiguration.envFile, basePath, undefined); } } + /** + * Resolves Python interpreter paths and handles the legacy pythonPath deprecation. + * + * @param workspaceFolder The workspace folder URI for variable resolution and interpreter detection + * @param debugConfiguration The launch configuration to update with resolved Python paths + */ protected async resolveAndUpdatePythonPath( workspaceFolder: Uri | undefined, debugConfiguration: LaunchRequestArguments, @@ -111,53 +137,105 @@ export abstract class BaseConfigurationResolver if (!debugConfiguration) { return; } + let interpreterDetailsTarget = workspaceFolder; + + if (debugConfiguration.program !== undefined) { + if (debugConfiguration.python === undefined) { + if (debugConfiguration.program === '${file}') { + // If program is ${file}, we cannot determine the interpreter yet + return; + } + // If program is a valid file, get interpreter for that file + if (fs.existsSync(debugConfiguration.program) && fs.statSync(debugConfiguration.program).isFile()) { + interpreterDetailsTarget = Uri.file(debugConfiguration.program); + } + } + } + // get the interpreter details in the context of either the workspace folder or the program file + const interpreterDetail = await getInterpreterDetails(interpreterDetailsTarget); + const interpreterPath = interpreterDetail?.path ?? (await getSettingsPythonPath(workspaceFolder)); + const resolvedInterpreterPath = interpreterPath ? interpreterPath[0] : interpreterPath; + + traceLog( + `resolveAndUpdatePythonPath - Initial state: ` + + `pythonPath='${debugConfiguration.pythonPath}', ` + + `python='${debugConfiguration.python}', ` + + `debugAdapterPython='${debugConfiguration.debugAdapterPython}', ` + + `debugLauncherPython='${debugConfiguration.debugLauncherPython}', ` + + `workspaceFolder='${workspaceFolder?.fsPath}'` + + `resolvedInterpreterPath='${resolvedInterpreterPath}'`, + ); + + // STEP 1: Resolve legacy pythonPath property (DEPRECATED) + // pythonPath will equal user set value, or getInterpreterDetails if undefined or set to command if (debugConfiguration.pythonPath === '${command:python.interpreterPath}' || !debugConfiguration.pythonPath) { - const interpreterDetail = await getInterpreterDetails(workspaceFolder); - const interpreterPath = interpreterDetail - ? interpreterDetail.path - : await getSettingsPythonPath(workspaceFolder); - debugConfiguration.pythonPath = interpreterPath ? interpreterPath[0] : interpreterPath; + this.pythonPathSource = PythonPathSource.settingsJson; + debugConfiguration.pythonPath = resolvedInterpreterPath; } else { - debugConfiguration.pythonPath = resolveVariables( - debugConfiguration.pythonPath ? debugConfiguration.pythonPath : undefined, + // User provided explicit pythonPath in launch.json + debugConfiguration.pythonPath = resolveWorkspaceVariables( + debugConfiguration.pythonPath, workspaceFolder?.fsPath, undefined, ); } + // STEP 2: Resolve current python property (CURRENT STANDARD) if (debugConfiguration.python === '${command:python.interpreterPath}') { + // if python is set to the command, resolve it this.pythonPathSource = PythonPathSource.settingsJson; - const interpreterDetail = await getInterpreterDetails(workspaceFolder); - const interpreterPath = interpreterDetail.path - ? interpreterDetail.path - : await getSettingsPythonPath(workspaceFolder); - debugConfiguration.python = interpreterPath ? interpreterPath[0] : interpreterPath; - } else if (debugConfiguration.python === undefined) { + debugConfiguration.python = resolvedInterpreterPath; + } else if (!debugConfiguration.python) { + // fallback to pythonPath if python undefined this.pythonPathSource = PythonPathSource.settingsJson; debugConfiguration.python = debugConfiguration.pythonPath; } else { + // User provided explicit python path in launch.json this.pythonPathSource = PythonPathSource.launchJson; - debugConfiguration.python = resolveVariables( - debugConfiguration.python ?? debugConfiguration.pythonPath, + debugConfiguration.python = resolveWorkspaceVariables( + debugConfiguration.python, workspaceFolder?.fsPath, undefined, ); } - if ( + // STEP 3: Set debug adapter and launcher Python paths (backwards compatible) + this.setDebugComponentPythonPaths(debugConfiguration); + + // STEP 4: Clean up - remove the deprecated pythonPath property + delete debugConfiguration.pythonPath; + } + + /** + * Sets debugAdapterPython and debugLauncherPython with backwards compatibility. + * Prefers pythonPath over python for these internal properties. + * + * @param debugConfiguration The debug configuration to update + */ + private setDebugComponentPythonPaths(debugConfiguration: LaunchRequestArguments): void { + const shouldSetDebugAdapter = debugConfiguration.debugAdapterPython === '${command:python.interpreterPath}' || - debugConfiguration.debugAdapterPython === undefined - ) { - debugConfiguration.debugAdapterPython = debugConfiguration.pythonPath ?? debugConfiguration.python; - } - if ( + debugConfiguration.debugAdapterPython === undefined; + + const shouldSetDebugLauncher = debugConfiguration.debugLauncherPython === '${command:python.interpreterPath}' || - debugConfiguration.debugLauncherPython === undefined - ) { - debugConfiguration.debugLauncherPython = debugConfiguration.pythonPath ?? debugConfiguration.python; + debugConfiguration.debugLauncherPython === undefined; + + // Default fallback path (prefer pythonPath for backwards compatibility) + const fallbackPath = debugConfiguration.pythonPath ?? debugConfiguration.python; + + if (debugConfiguration.pythonPath !== debugConfiguration.python) { + sendTelemetryEvent(EventName.DEPRECATED_CODE_PATH_USAGE, undefined, { + codePath: 'different_python_paths_in_debug_config', + }); } - delete debugConfiguration.pythonPath; + if (shouldSetDebugAdapter) { + debugConfiguration.debugAdapterPython = fallbackPath; + } + if (shouldSetDebugLauncher) { + debugConfiguration.debugLauncherPython = fallbackPath; + } } protected static debugOption(debugOptions: DebugOptions[], debugOption: DebugOptions): void { @@ -194,7 +272,7 @@ export abstract class BaseConfigurationResolver } else { // Expand ${workspaceFolder} variable first if necessary. pathMappings = pathMappings.map(({ localRoot: mappedLocalRoot, remoteRoot }) => { - const resolvedLocalRoot = resolveVariables(mappedLocalRoot, defaultLocalRoot, undefined); + const resolvedLocalRoot = resolveWorkspaceVariables(mappedLocalRoot, defaultLocalRoot, undefined); return { localRoot: resolvedLocalRoot || '', // TODO: Apply to remoteRoot too? diff --git a/src/extension/debugger/configuration/resolvers/launch.ts b/src/extension/debugger/configuration/resolvers/launch.ts index 85e89208..e991826f 100644 --- a/src/extension/debugger/configuration/resolvers/launch.ts +++ b/src/extension/debugger/configuration/resolvers/launch.ts @@ -8,7 +8,7 @@ import { getOSType, OSType } from '../../../common/platform'; import { getEnvFile } from '../../../common/settings'; import { DebuggerTypeName } from '../../../constants'; import { DebugOptions, DebugPurpose, LaunchRequestArguments } from '../../../types'; -import { resolveVariables } from '../utils/common'; +import { resolveWorkspaceVariables } from '../utils/common'; import { BaseConfigurationResolver } from './base'; import { getDebugEnvironmentVariables, getProgram } from './helper'; import { getConfiguration } from '../../../common/vscodeapi'; @@ -83,7 +83,7 @@ export class LaunchConfigurationResolver extends BaseConfigurationResolver('integrated.defaultProfile.windows'); + profiles = config.get('integrated.profiles.windows'); + } else if (platform === 'linux') { + defaultProfile = config.get('integrated.defaultProfile.linux'); + profiles = config.get('integrated.profiles.linux'); + } else if (platform === 'darwin') { + defaultProfile = config.get('integrated.defaultProfile.osx'); + profiles = config.get('integrated.profiles.osx'); + } + + if (!defaultProfile || !profiles) { + if (platform === 'win32') { + return "'"; // Default is powershell + } else { + return '"'; // Default is bash/zsh + } + } + + const profile = defaultProfile ? profiles[defaultProfile] : profiles[0]; + const shellPath = profile?.path || ''; + + if (/powershell|pwsh/i.test(shellPath)) { + return "'"; + } + if (/cmd\.exe$/i.test(shellPath)) { + return '"'; + } + if (/bash|zsh|fish/i.test(shellPath)) { + return '"'; + } + + return '"'; + } } diff --git a/src/extension/debugger/configuration/utils/common.ts b/src/extension/debugger/configuration/utils/common.ts index 59642dc6..c313c735 100644 --- a/src/extension/debugger/configuration/utils/common.ts +++ b/src/extension/debugger/configuration/utils/common.ts @@ -8,36 +8,63 @@ import { Uri, WorkspaceFolder } from 'vscode'; import { getWorkspaceFolder } from '../../../common/vscodeapi'; +import { sendTelemetryEvent } from '../../../telemetry'; +import { EventName } from '../../../telemetry/constants'; /** * @returns whether the provided parameter is a JavaScript String or not. */ function isString(str: any): str is string { - if (typeof str === 'string' || str instanceof String) { - return true; - } - - return false; + return typeof str === 'string' || str instanceof String; } -export function resolveVariables( +/** + * Resolves VS Code variable placeholders in a string value. + * + * Specifically handles: + * - `${workspaceFolder}` - replaced with the workspace folder path + * - `${env.VAR}` or `${env:VAR}` - replaced with empty string + * - Unknown variables - left as-is in the original `${variable}` format + * + * @param value The string containing variable placeholders to resolve + * @param rootFolder Fallback folder path to use if no workspace folder is available + * @param folder The workspace folder context for variable resolution + * @returns The string with variables resolved, or undefined if input was undefined + */ +export function resolveWorkspaceVariables( value: string | undefined, rootFolder: string | Uri | undefined, folder: WorkspaceFolder | undefined, ): string | undefined { - if (value) { - const workspaceFolder = folder ? getWorkspaceFolder(folder.uri) : undefined; - const variablesObject: { [key: string]: any } = {}; - variablesObject.workspaceFolder = workspaceFolder ? workspaceFolder.uri.fsPath : rootFolder; - - const regexp = /\$\{(.*?)\}/g; - return value.replace(regexp, (match: string, name: string) => { - const newValue = variablesObject[name]; - if (isString(newValue)) { - return newValue; - } - return match && (match.indexOf('env.') > 0 || match.indexOf('env:') > 0) ? '' : match; - }); + if (!value) { + return value; } - return value; + + // opt for folder with fallback to rootFolder + const workspaceFolder = folder ? getWorkspaceFolder(folder.uri) : undefined; + const workspaceFolderPath = workspaceFolder ? workspaceFolder.uri.fsPath : rootFolder; + + // Replace all ${variable} patterns + return value.replace(/\$\{([^}]+)\}/g, (match: string, variableName: string) => { + // Handle workspaceFolder variable + if (variableName === 'workspaceFolder' && isString(workspaceFolderPath)) { + // Track usage of this potentially deprecated code path + sendTelemetryEvent(EventName.DEPRECATED_CODE_PATH_USAGE, undefined, { + codePath: 'workspaceFolder_substitution', + }); + return workspaceFolderPath; + } + + // Replace environment variables with empty string + if (variableName.startsWith('env.') || variableName.startsWith('env:')) { + // Track usage of this potentially deprecated code path + sendTelemetryEvent(EventName.DEPRECATED_CODE_PATH_USAGE, undefined, { + codePath: 'env_variable_substitution', + }); + return ''; + } + + // Unknown variables are left unchanged + return match; + }); } diff --git a/src/extension/envExtApi.ts b/src/extension/envExtApi.ts new file mode 100644 index 00000000..dcb3da44 --- /dev/null +++ b/src/extension/envExtApi.ts @@ -0,0 +1,1289 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { + Disposable, + Event, + extensions, + FileChangeType, + LogOutputChannel, + MarkdownString, + TaskExecution, + Terminal, + TerminalOptions, + ThemeIcon, + Uri, +} from 'vscode'; + +/** + * The path to an icon, or a theme-specific configuration of icons. + */ +export type IconPath = + | Uri + | { + /** + * The icon path for the light theme. + */ + light: Uri; + /** + * The icon path for the dark theme. + */ + dark: Uri; + } + | ThemeIcon; + +/** + * Options for executing a Python executable. + */ +export interface PythonCommandRunConfiguration { + /** + * Path to the binary like `python.exe` or `python3` to execute. This should be an absolute path + * to an executable that can be spawned. + */ + executable: string; + + /** + * Arguments to pass to the python executable. These arguments will be passed on all execute calls. + * This is intended for cases where you might want to do interpreter specific flags. + */ + args?: string[]; +} + +/** + * Contains details on how to use a particular python environment + * + * Running In Terminal: + * 1. If {@link PythonEnvironmentExecutionInfo.activatedRun} is provided, then that will be used. + * 2. If {@link PythonEnvironmentExecutionInfo.activatedRun} is not provided, then: + * - If {@link PythonEnvironmentExecutionInfo.shellActivation} is provided and shell type is known, then that will be used. + * - If {@link PythonEnvironmentExecutionInfo.shellActivation} is provided and shell type is not known, then: + * - 'unknown' will be used if provided. + * - {@link PythonEnvironmentExecutionInfo.activation} will be used otherwise. + * - If {@link PythonEnvironmentExecutionInfo.shellActivation} is not provided, then {@link PythonEnvironmentExecutionInfo.activation} will be used. + * - If {@link PythonEnvironmentExecutionInfo.activation} is not provided, then {@link PythonEnvironmentExecutionInfo.run} will be used. + * + * Creating a Terminal: + * 1. If {@link PythonEnvironmentExecutionInfo.shellActivation} is provided and shell type is known, then that will be used. + * 2. If {@link PythonEnvironmentExecutionInfo.shellActivation} is provided and shell type is not known, then {@link PythonEnvironmentExecutionInfo.activation} will be used. + * 3. If {@link PythonEnvironmentExecutionInfo.shellActivation} is not provided, then: + * - 'unknown' will be used if provided. + * - {@link PythonEnvironmentExecutionInfo.activation} will be used otherwise. + * 4. If {@link PythonEnvironmentExecutionInfo.activation} is not provided, then {@link PythonEnvironmentExecutionInfo.run} will be used. + * + */ +export interface PythonEnvironmentExecutionInfo { + /** + * Details on how to run the python executable. + */ + run: PythonCommandRunConfiguration; + + /** + * Details on how to run the python executable after activating the environment. + * If set this will overrides the {@link PythonEnvironmentExecutionInfo.run} command. + */ + activatedRun?: PythonCommandRunConfiguration; + + /** + * Details on how to activate an environment. + */ + activation?: PythonCommandRunConfiguration[]; + + /** + * Details on how to activate an environment using a shell specific command. + * If set this will override the {@link PythonEnvironmentExecutionInfo.activation}. + * 'unknown' is used if shell type is not known. + * If 'unknown' is not provided and shell type is not known then + * {@link PythonEnvironmentExecutionInfo.activation} if set. + */ + shellActivation?: Map; + + /** + * Details on how to deactivate an environment. + */ + deactivation?: PythonCommandRunConfiguration[]; + + /** + * Details on how to deactivate an environment using a shell specific command. + * If set this will override the {@link PythonEnvironmentExecutionInfo.deactivation} property. + * 'unknown' is used if shell type is not known. + * If 'unknown' is not provided and shell type is not known then + * {@link PythonEnvironmentExecutionInfo.deactivation} if set. + */ + shellDeactivation?: Map; +} + +/** + * Interface representing the ID of a Python environment. + */ +export interface PythonEnvironmentId { + /** + * The unique identifier of the Python environment. + */ + id: string; + + /** + * The ID of the manager responsible for the Python environment. + */ + managerId: string; +} + +/** + * Display information for an environment group. + */ +export interface EnvironmentGroupInfo { + /** + * The name of the environment group. This is used as an identifier for the group. + * + * Note: The first instance of the group with the given name will be used in the UI. + */ + readonly name: string; + + /** + * The description of the environment group. + */ + readonly description?: string; + + /** + * The tooltip for the environment group, which can be a string or a Markdown string. + */ + readonly tooltip?: string | MarkdownString; + + /** + * The icon path for the environment group, which can be a string, Uri, or an object with light and dark theme paths. + */ + readonly iconPath?: IconPath; +} + +/** + * Interface representing information about a Python environment. + */ +export interface PythonEnvironmentInfo { + /** + * The name of the Python environment. + */ + readonly name: string; + + /** + * The display name of the Python environment. + */ + readonly displayName: string; + + /** + * The short display name of the Python environment. + */ + readonly shortDisplayName?: string; + + /** + * The display path of the Python environment. + */ + readonly displayPath: string; + + /** + * The version of the Python environment. + */ + readonly version: string; + + /** + * Path to the python binary or environment folder. + */ + readonly environmentPath: Uri; + + /** + * The description of the Python environment. + */ + readonly description?: string; + + /** + * The tooltip for the Python environment, which can be a string or a Markdown string. + */ + readonly tooltip?: string | MarkdownString; + + /** + * The icon path for the Python environment, which can be a string, Uri, or an object with light and dark theme paths. + */ + readonly iconPath?: IconPath; + + /** + * Information on how to execute the Python environment. This is required for executing Python code in the environment. + */ + readonly execInfo: PythonEnvironmentExecutionInfo; + + /** + * `sys.prefix` is the path to the base directory of the Python installation. Typically obtained by executing `sys.prefix` in the Python interpreter. + * This is required by extension like Jupyter, Pylance, and other extensions to provide better experience with python. + */ + readonly sysPrefix: string; + + /** + * Optional `group` for this environment. This is used to group environments in the Environment Manager UI. + */ + readonly group?: string | EnvironmentGroupInfo; +} + +/** + * Interface representing a Python environment. + */ +export interface PythonEnvironment extends PythonEnvironmentInfo { + /** + * The ID of the Python environment. + */ + readonly envId: PythonEnvironmentId; +} + +/** + * Type representing the scope for setting a Python environment. + * Can be undefined or a URI. + */ +export type SetEnvironmentScope = undefined | Uri | Uri[]; + +/** + * Type representing the scope for getting a Python environment. + * Can be undefined or a URI. + */ +export type GetEnvironmentScope = undefined | Uri; + +/** + * Type representing the scope for creating a Python environment. + * Can be a Python project or 'global'. + */ +export type CreateEnvironmentScope = Uri | Uri[] | 'global'; +/** + * The scope for which environments are to be refreshed. + * - `undefined`: Search for environments globally and workspaces. + * - {@link Uri}: Environments in the workspace/folder or associated with the Uri. + */ +export type RefreshEnvironmentsScope = Uri | undefined; + +/** + * The scope for which environments are required. + * - `"all"`: All environments. + * - `"global"`: Python installations that are usually a base for creating virtual environments. + * - {@link Uri}: Environments for the workspace/folder/file pointed to by the Uri. + */ +export type GetEnvironmentsScope = Uri | 'all' | 'global'; + +/** + * Event arguments for when the current Python environment changes. + */ +export type DidChangeEnvironmentEventArgs = { + /** + * The URI of the environment that changed. + */ + readonly uri: Uri | undefined; + + /** + * The old Python environment before the change. + */ + readonly old: PythonEnvironment | undefined; + + /** + * The new Python environment after the change. + */ + readonly new: PythonEnvironment | undefined; +}; + +/** + * Enum representing the kinds of environment changes. + */ +export enum EnvironmentChangeKind { + /** + * Indicates that an environment was added. + */ + add = 'add', + + /** + * Indicates that an environment was removed. + */ + remove = 'remove', +} + +/** + * Event arguments for when the list of Python environments changes. + */ +export type DidChangeEnvironmentsEventArgs = { + /** + * The kind of change that occurred (add or remove). + */ + kind: EnvironmentChangeKind; + + /** + * The Python environment that was added or removed. + */ + environment: PythonEnvironment; +}[]; + +/** + * Type representing the context for resolving a Python environment. + */ +export type ResolveEnvironmentContext = Uri; + +export interface QuickCreateConfig { + /** + * The description of the quick create step. + */ + readonly description: string; + + /** + * The detail of the quick create step. + */ + readonly detail?: string; +} + +/** + * Interface representing an environment manager. + */ +export interface EnvironmentManager { + /** + * The name of the environment manager. Allowed characters (a-z, A-Z, 0-9, -, _). + */ + readonly name: string; + + /** + * The display name of the environment manager. + */ + readonly displayName?: string; + + /** + * The preferred package manager ID for the environment manager. This is a combination + * of publisher id, extension id, and {@link EnvironmentManager.name package manager name}. + * `.:` + * + * @example + * 'ms-python.python:pip' + */ + readonly preferredPackageManagerId: string; + + /** + * The description of the environment manager. + */ + readonly description?: string; + + /** + * The tooltip for the environment manager, which can be a string or a Markdown string. + */ + readonly tooltip?: string | MarkdownString | undefined; + + /** + * The icon path for the environment manager, which can be a string, Uri, or an object with light and dark theme paths. + */ + readonly iconPath?: IconPath; + + /** + * The log output channel for the environment manager. + */ + readonly log?: LogOutputChannel; + + /** + * The quick create details for the environment manager. Having this method also enables the quick create feature + * for the environment manager. Should Implement {@link EnvironmentManager.create} to support quick create. + */ + quickCreateConfig?(): QuickCreateConfig | undefined; + + /** + * Creates a new Python environment within the specified scope. Create should support adding a .gitignore file if it creates a folder within the workspace. If a manager does not support environment creation, do not implement this method; the UI disables "create" options when `this.manager.create === undefined`. + * @param scope - The scope within which to create the environment. + * @param options - Optional parameters for creating the Python environment. + * @returns A promise that resolves to the created Python environment, or undefined if creation failed. + */ + create?(scope: CreateEnvironmentScope, options?: CreateEnvironmentOptions): Promise; + + /** + * Removes the specified Python environment. + * @param environment - The Python environment to remove. + * @returns A promise that resolves when the environment is removed. + */ + remove?(environment: PythonEnvironment): Promise; + + /** + * Refreshes the list of Python environments within the specified scope. + * @param scope - The scope within which to refresh environments. + * @returns A promise that resolves when the refresh is complete. + */ + refresh(scope: RefreshEnvironmentsScope): Promise; + + /** + * Retrieves a list of Python environments within the specified scope. + * @param scope - The scope within which to retrieve environments. + * @returns A promise that resolves to an array of Python environments. + */ + getEnvironments(scope: GetEnvironmentsScope): Promise; + + /** + * Event that is fired when the list of Python environments changes. + */ + onDidChangeEnvironments?: Event; + + /** + * Sets the current Python environment within the specified scope. + * @param scope - The scope within which to set the environment. + * @param environment - The Python environment to set. If undefined, the environment is unset. + * @returns A promise that resolves when the environment is set. + */ + set(scope: SetEnvironmentScope, environment?: PythonEnvironment): Promise; + + /** + * Retrieves the current Python environment within the specified scope. + * @param scope - The scope within which to retrieve the environment. + * @returns A promise that resolves to the current Python environment, or undefined if none is set. + */ + get(scope: GetEnvironmentScope): Promise; + + /** + * Event that is fired when the current Python environment changes. + */ + onDidChangeEnvironment?: Event; + + /** + * Resolves the specified Python environment. The environment can be either a {@link PythonEnvironment} or a {@link Uri} context. + * + * This method is used to obtain a fully detailed {@link PythonEnvironment} object. The input can be: + * - A {@link PythonEnvironment} object, which might be missing key details such as {@link PythonEnvironment.execInfo}. + * - A {@link Uri} object, which typically represents either: + * - A folder that contains the Python environment. + * - The path to a Python executable. + * + * @param context - The context for resolving the environment, which can be a {@link PythonEnvironment} or a {@link Uri}. + * @returns A promise that resolves to the fully detailed {@link PythonEnvironment}, or `undefined` if the environment cannot be resolved. + */ + resolve(context: ResolveEnvironmentContext): Promise; + + /** + * Clears the environment manager's cache. + * + * @returns A promise that resolves when the cache is cleared. + */ + clearCache?(): Promise; +} + +/** + * Interface representing a package ID. + */ +export interface PackageId { + /** + * The ID of the package. + */ + id: string; + + /** + * The ID of the package manager. + */ + managerId: string; + + /** + * The ID of the environment in which the package is installed. + */ + environmentId: string; +} + +/** + * Interface representing package information. + */ +export interface PackageInfo { + /** + * The name of the package. + */ + readonly name: string; + + /** + * The display name of the package. + */ + readonly displayName: string; + + /** + * The version of the package. + */ + readonly version?: string; + + /** + * The description of the package. + */ + readonly description?: string; + + /** + * The tooltip for the package, which can be a string or a Markdown string. + */ + readonly tooltip?: string | MarkdownString | undefined; + + /** + * The icon path for the package, which can be a string, Uri, or an object with light and dark theme paths. + */ + readonly iconPath?: IconPath; + + /** + * The URIs associated with the package. + */ + readonly uris?: readonly Uri[]; +} + +/** + * Interface representing a package. + */ +export interface Package extends PackageInfo { + /** + * The ID of the package. + */ + readonly pkgId: PackageId; +} + +/** + * Enum representing the kinds of package changes. + */ +export enum PackageChangeKind { + /** + * Indicates that a package was added. + */ + add = 'add', + + /** + * Indicates that a package was removed. + */ + remove = 'remove', +} + +/** + * Event arguments for when packages change. + */ +export interface DidChangePackagesEventArgs { + /** + * The Python environment in which the packages changed. + */ + environment: PythonEnvironment; + + /** + * The package manager responsible for the changes. + */ + manager: PackageManager; + + /** + * The list of changes, each containing the kind of change and the package affected. + */ + changes: { kind: PackageChangeKind; pkg: Package }[]; +} + +/** + * Interface representing a package manager. + */ +export interface PackageManager { + /** + * The name of the package manager. Allowed characters (a-z, A-Z, 0-9, -, _). + */ + name: string; + + /** + * The display name of the package manager. + */ + displayName?: string; + + /** + * The description of the package manager. + */ + description?: string; + + /** + * The tooltip for the package manager, which can be a string or a Markdown string. + */ + tooltip?: string | MarkdownString | undefined; + + /** + * The icon path for the package manager, which can be a string, Uri, or an object with light and dark theme paths. + */ + iconPath?: IconPath; + + /** + * The log output channel for the package manager. + */ + log?: LogOutputChannel; + + /** + * Installs/Uninstall packages in the specified Python environment. + * @param environment - The Python environment in which to install packages. + * @param options - Options for managing packages. + * @returns A promise that resolves when the installation is complete. + */ + manage(environment: PythonEnvironment, options: PackageManagementOptions): Promise; + + /** + * Refreshes the package list for the specified Python environment. + * @param environment - The Python environment for which to refresh the package list. + * @returns A promise that resolves when the refresh is complete. + */ + refresh(environment: PythonEnvironment): Promise; + + /** + * Retrieves the list of packages for the specified Python environment. + * @param environment - The Python environment for which to retrieve packages. + * @returns An array of packages, or undefined if the packages could not be retrieved. + */ + getPackages(environment: PythonEnvironment): Promise; + + /** + * Event that is fired when packages change. + */ + onDidChangePackages?: Event; + + /** + * Clears the package manager's cache. + * @returns A promise that resolves when the cache is cleared. + */ + clearCache?(): Promise; +} + +/** + * Interface representing a Python project. + */ +export interface PythonProject { + /** + * The name of the Python project. + */ + readonly name: string; + + /** + * The URI of the Python project. + */ + readonly uri: Uri; + + /** + * The description of the Python project. + */ + readonly description?: string; + + /** + * The tooltip for the Python project, which can be a string or a Markdown string. + */ + readonly tooltip?: string | MarkdownString; +} + +/** + * Options for creating a Python project. + */ +export interface PythonProjectCreatorOptions { + /** + * The name of the Python project. + */ + name: string; + + /** + * Path provided as the root for the project. + */ + rootUri: Uri; + + /** + * Boolean indicating whether the project should be created without any user input. + */ + quickCreate?: boolean; +} + +/** + * Interface representing a creator for Python projects. + */ +export interface PythonProjectCreator { + /** + * The name of the Python project creator. + */ + readonly name: string; + + /** + * The display name of the Python project creator. + */ + readonly displayName?: string; + + /** + * The description of the Python project creator. + */ + readonly description?: string; + + /** + * The tooltip for the Python project creator, which can be a string or a Markdown string. + */ + readonly tooltip?: string | MarkdownString; + + /** + * Creates a new Python project(s) or, if files are not a project, returns Uri(s) to the created files. + * Anything that needs its own python environment constitutes a project. + * @param options Optional parameters for creating the Python project. + * @returns A promise that resolves to one of the following: + * - PythonProject or PythonProject[]: when a single or multiple projects are created. + * - Uri or Uri[]: when files are created that do not constitute a project. + * - undefined: if project creation fails. + */ + create(options?: PythonProjectCreatorOptions): Promise; + + /** + * A flag indicating whether the project creator supports quick create where no user input is required. + */ + readonly supportsQuickCreate?: boolean; +} + +/** + * Event arguments for when Python projects change. + */ +export interface DidChangePythonProjectsEventArgs { + /** + * The list of Python projects that were added. + */ + added: PythonProject[]; + + /** + * The list of Python projects that were removed. + */ + removed: PythonProject[]; +} + +export type PackageManagementOptions = + | { + /** + * Upgrade the packages if they are already installed. + */ + upgrade?: boolean; + + /** + * Show option to skip package installation or uninstallation. + */ + showSkipOption?: boolean; + /** + * The list of packages to install. + */ + install: string[]; + + /** + * The list of packages to uninstall. + */ + uninstall?: string[]; + } + | { + /** + * Upgrade the packages if they are already installed. + */ + upgrade?: boolean; + + /** + * Show option to skip package installation or uninstallation. + */ + showSkipOption?: boolean; + /** + * The list of packages to install. + */ + install?: string[]; + + /** + * The list of packages to uninstall. + */ + uninstall: string[]; + }; + +/** + * Options for creating a Python environment. + */ +export interface CreateEnvironmentOptions { + /** + * Provides some context about quick create based on user input. + * - if true, the environment should be created without any user input or prompts. + * - if false, the environment creation can show user input or prompts. + * This also means user explicitly skipped the quick create option. + * - if undefined, the environment creation can show user input or prompts. + * You can show quick create option to the user if you support it. + */ + quickCreate?: boolean; + /** + * Packages to install in addition to the automatically picked packages as a part of creating environment. + */ + additionalPackages?: string[]; +} + +/** + * Object representing the process started using run in background API. + */ +export interface PythonProcess { + /** + * The process ID of the Python process. + */ + readonly pid?: number; + + /** + * The standard input of the Python process. + */ + readonly stdin: NodeJS.WritableStream; + + /** + * The standard output of the Python process. + */ + readonly stdout: NodeJS.ReadableStream; + + /** + * The standard error of the Python process. + */ + readonly stderr: NodeJS.ReadableStream; + + /** + * Kills the Python process. + */ + kill(): void; + + /** + * Event that is fired when the Python process exits. + */ + onExit(listener: (code: number | null, signal: NodeJS.Signals | null) => void): void; +} + +export interface PythonEnvironmentManagerRegistrationApi { + /** + * Register an environment manager implementation. + * + * @param manager Environment Manager implementation to register. + * @returns A disposable that can be used to unregister the environment manager. + * @see {@link EnvironmentManager} + */ + registerEnvironmentManager(manager: EnvironmentManager): Disposable; +} + +export interface PythonEnvironmentItemApi { + /** + * Create a Python environment item from the provided environment info. This item is used to interact + * with the environment. + * + * @param info Some details about the environment like name, version, etc. needed to interact with the environment. + * @param manager The environment manager to associate with the environment. + * @returns The Python environment. + */ + createPythonEnvironmentItem(info: PythonEnvironmentInfo, manager: EnvironmentManager): PythonEnvironment; +} + +export interface PythonEnvironmentManagementApi { + /** + * Create a Python environment using environment manager associated with the scope. + * + * @param scope Where the environment is to be created. + * @param options Optional parameters for creating the Python environment. + * @returns The Python environment created. `undefined` if not created. + */ + createEnvironment( + scope: CreateEnvironmentScope, + options?: CreateEnvironmentOptions, + ): Promise; + + /** + * Remove a Python environment. + * + * @param environment The Python environment to remove. + * @returns A promise that resolves when the environment has been removed. + */ + removeEnvironment(environment: PythonEnvironment): Promise; +} + +export interface PythonEnvironmentsApi { + /** + * Initiates a refresh of Python environments within the specified scope. + * @param scope - The scope within which to search for environments. + * @returns A promise that resolves when the search is complete. + */ + refreshEnvironments(scope: RefreshEnvironmentsScope): Promise; + + /** + * Retrieves a list of Python environments within the specified scope. + * @param scope - The scope within which to retrieve environments. + * @returns A promise that resolves to an array of Python environments. + */ + getEnvironments(scope: GetEnvironmentsScope): Promise; + + /** + * Event that is fired when the list of Python environments changes. + * @see {@link DidChangeEnvironmentsEventArgs} + */ + onDidChangeEnvironments: Event; + + /** + * This method is used to get the details missing from a PythonEnvironment. Like + * {@link PythonEnvironment.execInfo} and other details. + * + * @param context : The PythonEnvironment or Uri for which details are required. + */ + resolveEnvironment(context: ResolveEnvironmentContext): Promise; +} + +export interface PythonProjectEnvironmentApi { + /** + * Sets the current Python environment within the specified scope. + * @param scope - The scope within which to set the environment. + * @param environment - The Python environment to set. If undefined, the environment is unset. + */ + setEnvironment(scope: SetEnvironmentScope, environment?: PythonEnvironment): Promise; + + /** + * Retrieves the current Python environment within the specified scope. + * @param scope - The scope within which to retrieve the environment. + * @returns A promise that resolves to the current Python environment, or undefined if none is set. + */ + getEnvironment(scope: GetEnvironmentScope): Promise; + + /** + * Event that is fired when the selected Python environment changes for Project, Folder or File. + * @see {@link DidChangeEnvironmentEventArgs} + */ + onDidChangeEnvironment: Event; +} + +export interface PythonEnvironmentManagerApi + extends PythonEnvironmentManagerRegistrationApi, + PythonEnvironmentItemApi, + PythonEnvironmentManagementApi, + PythonEnvironmentsApi, + PythonProjectEnvironmentApi {} + +export interface PythonPackageManagerRegistrationApi { + /** + * Register a package manager implementation. + * + * @param manager Package Manager implementation to register. + * @returns A disposable that can be used to unregister the package manager. + * @see {@link PackageManager} + */ + registerPackageManager(manager: PackageManager): Disposable; +} + +export interface PythonPackageGetterApi { + /** + * Refresh the list of packages in a Python Environment. + * + * @param environment The Python Environment for which the list of packages is to be refreshed. + * @returns A promise that resolves when the list of packages has been refreshed. + */ + refreshPackages(environment: PythonEnvironment): Promise; + + /** + * Get the list of packages in a Python Environment. + * + * @param environment The Python Environment for which the list of packages is required. + * @returns The list of packages in the Python Environment. + */ + getPackages(environment: PythonEnvironment): Promise; + + /** + * Event raised when the list of packages in a Python Environment changes. + * @see {@link DidChangePackagesEventArgs} + */ + onDidChangePackages: Event; +} + +export interface PythonPackageItemApi { + /** + * Create a package item from the provided package info. + * + * @param info The package info. + * @param environment The Python Environment in which the package is installed. + * @param manager The package manager that installed the package. + * @returns The package item. + */ + createPackageItem(info: PackageInfo, environment: PythonEnvironment, manager: PackageManager): Package; +} + +export interface PythonPackageManagementApi { + /** + * Install/Uninstall packages into a Python Environment. + * + * @param environment The Python Environment into which packages are to be installed. + * @param packages The packages to install. + * @param options Options for installing packages. + */ + managePackages(environment: PythonEnvironment, options: PackageManagementOptions): Promise; +} + +export interface PythonPackageManagerApi + extends PythonPackageManagerRegistrationApi, + PythonPackageGetterApi, + PythonPackageManagementApi, + PythonPackageItemApi {} + +export interface PythonProjectCreationApi { + /** + * Register a Python project creator. + * + * @param creator The project creator to register. + * @returns A disposable that can be used to unregister the project creator. + * @see {@link PythonProjectCreator} + */ + registerPythonProjectCreator(creator: PythonProjectCreator): Disposable; +} +export interface PythonProjectGetterApi { + /** + * Get all python projects. + */ + getPythonProjects(): readonly PythonProject[]; + + /** + * Get the python project for a given URI. + * + * @param uri The URI of the project + * @returns The project or `undefined` if not found. + */ + getPythonProject(uri: Uri): PythonProject | undefined; +} + +export interface PythonProjectModifyApi { + /** + * Add a python project or projects to the list of projects. + * + * @param projects The project or projects to add. + */ + addPythonProject(projects: PythonProject | PythonProject[]): void; + + /** + * Remove a python project from the list of projects. + * + * @param project The project to remove. + */ + removePythonProject(project: PythonProject): void; + + /** + * Event raised when python projects are added or removed. + * @see {@link DidChangePythonProjectsEventArgs} + */ + onDidChangePythonProjects: Event; +} + +/** + * The API for interacting with Python projects. A project in python is any folder or file that is a contained + * in some manner. For example, a PEP-723 compliant file can be treated as a project. A folder with a `pyproject.toml`, + * or just python files can be treated as a project. All this allows you to do is set a python environment for that project. + * + * By default all `vscode.workspace.workspaceFolders` are treated as projects. + */ +export interface PythonProjectApi extends PythonProjectCreationApi, PythonProjectGetterApi, PythonProjectModifyApi {} + +export interface PythonTerminalCreateOptions extends TerminalOptions { + /** + * Whether to disable activation on create. + */ + disableActivation?: boolean; +} + +export interface PythonTerminalCreateApi { + /** + * Creates a terminal and activates any (activatable) environment for the terminal. + * + * @param environment The Python environment to activate. + * @param options Options for creating the terminal. + * + * Note: Non-activatable environments have no effect on the terminal. + */ + createTerminal(environment: PythonEnvironment, options: PythonTerminalCreateOptions): Promise; +} + +/** + * Options for running a Python script or module in a terminal. + * + * Example: + * * Running Script: `python myscript.py --arg1` + * ```typescript + * { + * args: ["myscript.py", "--arg1"] + * } + * ``` + * * Running a module: `python -m my_module --arg1` + * ```typescript + * { + * args: ["-m", "my_module", "--arg1"] + * } + * ``` + */ +export interface PythonTerminalExecutionOptions { + /** + * Current working directory for the terminal. This in only used to create the terminal. + */ + cwd: string | Uri; + + /** + * Arguments to pass to the python executable. + */ + args?: string[]; + + /** + * Set `true` to show the terminal. + */ + show?: boolean; +} + +export interface PythonTerminalRunApi { + /** + * Runs a Python script or module in a terminal. This API will create a terminal if one is not available to use. + * If a terminal is available, it will be used to run the script or module. + * + * Note: + * - If you restart VS Code, this will create a new terminal, this is a limitation of VS Code. + * - If you close the terminal, this will create a new terminal. + * - In cases of multi-root/project scenario, it will create a separate terminal for each project. + */ + runInTerminal(environment: PythonEnvironment, options: PythonTerminalExecutionOptions): Promise; + + /** + * Runs a Python script or module in a dedicated terminal. This API will create a terminal if one is not available to use. + * If a terminal is available, it will be used to run the script or module. This terminal will be dedicated to the script, + * and selected based on the `terminalKey`. + * + * @param terminalKey A unique key to identify the terminal. For scripts you can use the Uri of the script file. + */ + runInDedicatedTerminal( + terminalKey: Uri | string, + environment: PythonEnvironment, + options: PythonTerminalExecutionOptions, + ): Promise; +} + +/** + * Options for running a Python task. + * + * Example: + * * Running Script: `python myscript.py --arg1` + * ```typescript + * { + * args: ["myscript.py", "--arg1"] + * } + * ``` + * * Running a module: `python -m my_module --arg1` + * ```typescript + * { + * args: ["-m", "my_module", "--arg1"] + * } + * ``` + */ +export interface PythonTaskExecutionOptions { + /** + * Name of the task to run. + */ + name: string; + + /** + * Arguments to pass to the python executable. + */ + args: string[]; + + /** + * The Python project to use for the task. + */ + project?: PythonProject; + + /** + * Current working directory for the task. Default is the project directory for the script being run. + */ + cwd?: string; + + /** + * Environment variables to set for the task. + */ + env?: { [key: string]: string }; +} + +export interface PythonTaskRunApi { + /** + * Run a Python script or module as a task. + * + */ + runAsTask(environment: PythonEnvironment, options: PythonTaskExecutionOptions): Promise; +} + +/** + * Options for running a Python script or module in the background. + */ +export interface PythonBackgroundRunOptions { + /** + * The Python environment to use for running the script or module. + */ + args: string[]; + + /** + * Current working directory for the script or module. Default is the project directory for the script being run. + */ + cwd?: string; + + /** + * Environment variables to set for the script or module. + */ + env?: { [key: string]: string | undefined }; +} +export interface PythonBackgroundRunApi { + /** + * Run a Python script or module in the background. This API will create a new process to run the script or module. + */ + runInBackground(environment: PythonEnvironment, options: PythonBackgroundRunOptions): Promise; +} + +export interface PythonExecutionApi + extends PythonTerminalCreateApi, + PythonTerminalRunApi, + PythonTaskRunApi, + PythonBackgroundRunApi {} + +/** + * Event arguments for when the monitored `.env` files or any other sources change. + */ +export interface DidChangeEnvironmentVariablesEventArgs { + /** + * The URI of the file that changed. No `Uri` means a non-file source of environment variables changed. + */ + uri?: Uri; + + /** + * The type of change that occurred. + */ + changeType: FileChangeType; +} + +export interface PythonEnvironmentVariablesApi { + /** + * Get environment variables for a workspace. This picks up `.env` file from the root of the + * workspace. + * + * Order of overrides: + * 1. `baseEnvVar` if given or `process.env` + * 2. `.env` file from the "python.envFile" setting in the workspace. + * 3. `.env` file at the root of the python project. + * 4. `overrides` in the order provided. + * + * @param uri The URI of the project, workspace or a file in a for which environment variables are required. + * @param overrides Additional environment variables to override the defaults. + * @param baseEnvVar The base environment variables that should be used as a starting point. + */ + getEnvironmentVariables( + uri: Uri | undefined, + overrides?: ({ [key: string]: string | undefined } | Uri)[], + baseEnvVar?: { [key: string]: string | undefined }, + ): Promise<{ [key: string]: string | undefined }>; + + /** + * Event raised when `.env` file changes or any other monitored source of env variable changes. + */ + onDidChangeEnvironmentVariables: Event; +} + +/** + * The API for interacting with Python environments, package managers, and projects. + */ +export interface PythonEnvironmentApi + extends PythonEnvironmentManagerApi, + PythonPackageManagerApi, + PythonProjectApi, + PythonExecutionApi, + PythonEnvironmentVariablesApi {} + +export const PEVSC_EXTENSION_ID = 'ms-python.vscode-python-envs'; + +// export interface PythonEnvsExtension { +// api: () => Promise; +// } + +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace PythonEnvsExtension { + /** + * Returns the API exposed by the Python extension in VS Code. + */ + export async function api(): Promise { + const extension = extensions.getExtension(PEVSC_EXTENSION_ID); + if (extension === undefined) { + throw new Error(`Python extension is not installed or is disabled`); + } + if (!extension.isActive) { + await extension.activate(); + } + const pythonApi: PythonEnvironmentApi = extension.exports; + return pythonApi; + } +} diff --git a/src/extension/extensionInit.ts b/src/extension/extensionInit.ts index c4f52b6c..3e188af2 100644 --- a/src/extension/extensionInit.ts +++ b/src/extension/extensionInit.ts @@ -4,6 +4,7 @@ 'use strict'; import { + commands, ConfigurationChangeEvent, debug, DebugConfigurationProviderTriggerKind, @@ -54,6 +55,7 @@ import { registerHexDebugVisualizationTreeProvider } from './debugger/visualizer import { PythonInlineValueProvider } from './debugger/inlineValue/pythonInlineValueProvider'; import { traceLog } from './common/log/logging'; import { registerNoConfigDebug } from './noConfigDebugInit'; +import { OnErrorsActions, resolveOnErrorsAction } from './common/onErrorsAction'; export async function registerDebugger(context: IExtensionContext): Promise { const childProcessAttachService = new ChildProcessAttachService(); @@ -87,6 +89,15 @@ export async function registerDebugger(context: IExtensionContext): Promise { + const action = await resolveOnErrorsAction(); + switch (action) { + case OnErrorsActions.showErrors: + await commands.executeCommand('workbench.panel.markers.view.focus'); + return; + + case OnErrorsActions.abort: + return; + } traceLog("Debugging using the editor button 'Debug in terminal'"); sendTelemetryEvent(EventName.DEBUG_IN_TERMINAL_BUTTON); const interpreter = await getInterpreterDetails(file); @@ -101,6 +112,15 @@ export async function registerDebugger(context: IExtensionContext): Promise { + const action = await resolveOnErrorsAction(); + switch (action) { + case OnErrorsActions.showErrors: + await commands.executeCommand('workbench.panel.markers.view.focus'); + return; + + case OnErrorsActions.abort: + return; + } traceLog("Debugging using the editor button 'Debug using the launch.json'"); sendTelemetryEvent(EventName.DEBUG_USING_LAUNCH_CONFIG_BUTTON); const interpreter = await getInterpreterDetails(file); diff --git a/src/extension/noConfigDebugInit.ts b/src/extension/noConfigDebugInit.ts index 49bc506a..23ed3790 100644 --- a/src/extension/noConfigDebugInit.ts +++ b/src/extension/noConfigDebugInit.ts @@ -77,7 +77,13 @@ export async function registerNoConfigDebug( const noConfigScriptsDir = path.join(extPath, 'bundled', 'scripts', 'noConfigScripts'); const pathSeparator = process.platform === 'win32' ? ';' : ':'; - collection.append('PATH', `${pathSeparator}${noConfigScriptsDir}`); + + // Check if the current PATH already ends with a path separator to avoid double separators + const currentPath = process.env.PATH || ''; + const needsSeparator = currentPath.length > 0 && !currentPath.endsWith(pathSeparator); + const pathValueToAppend = needsSeparator ? `${pathSeparator}${noConfigScriptsDir}` : noConfigScriptsDir; + + collection.append('PATH', pathValueToAppend); const bundledDebugPath = path.join(extPath, 'bundled', 'libs', 'debugpy'); collection.replace('BUNDLED_DEBUGPY_PATH', bundledDebugPath); @@ -87,7 +93,7 @@ export async function registerNoConfigDebug( ); // create file system watcher for the debuggerAdapterEndpointFolder for when the communication port is written - const fileSystemWatcher = createFileSystemWatcher(new RelativePattern(tempDirPath, '**/*')); + const fileSystemWatcher = createFileSystemWatcher(new RelativePattern(tempDirPath, '**/*.txt')); const fileCreationEvent = fileSystemWatcher.onDidCreate(async (uri) => { sendTelemetryEvent(EventName.DEBUG_SESSION_START, undefined, { trigger: 'noConfig' as TriggerType, @@ -95,13 +101,13 @@ export async function registerNoConfigDebug( const filePath = uri.fsPath; fs.readFile(filePath, (err, data) => { - const dataParse = data.toString(); if (err) { traceError(`Error reading debuggerAdapterEndpoint.txt file: ${err}`); return; } try { // parse the client port + const dataParse = data.toString(); const jsonData = JSON.parse(dataParse); const clientPort = jsonData.client?.port; traceVerbose(`Parsed client port: ${clientPort}`); diff --git a/src/extension/telemetry/constants.ts b/src/extension/telemetry/constants.ts index 94ff6643..d75bb898 100644 --- a/src/extension/telemetry/constants.ts +++ b/src/extension/telemetry/constants.ts @@ -24,4 +24,5 @@ export enum EventName { USE_REPORT_ISSUE_COMMAND = 'USE_REPORT_ISSUE_COMMAND', DEBUGGER_PYTHON_37_DEPRECATED = 'DEBUGGER_PYTHON_37_DEPRECATED', DEBUGGER_SHOW_PYTHON_INLINE_VALUES = 'DEBUGGER_SHOW_PYTHON_INLINE_VALUES', + DEPRECATED_CODE_PATH_USAGE = 'DEPRECATED_CODE_PATH_USAGE', } diff --git a/src/extension/telemetry/index.ts b/src/extension/telemetry/index.ts index 5be026fe..ef647b4e 100644 --- a/src/extension/telemetry/index.ts +++ b/src/extension/telemetry/index.ts @@ -691,4 +691,21 @@ export interface IEventNamePropertyMapping { "DEBUGGER_SHOW_PYTHON_INLINE_VALUES" : { "owner": "eleanorjboyd" } */ [EventName.DEBUGGER_SHOW_PYTHON_INLINE_VALUES]: never | undefined; + /** + * Telemetry event sent when potentially deprecated code paths are executed. + */ + /* __GDPR__ + "deprecated_code_path_usage" : { + "codepath" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "owner": "eleanorjboyd" } + } + */ + [EventName.DEPRECATED_CODE_PATH_USAGE]: { + /** + * Identifier for the specific deprecated code path that was executed. + * Examples: 'workspaceFolder_substitution', 'env_variable_substitution' + * + * @type {string} + */ + codePath: string; + }; } diff --git a/src/test/constants.ts b/src/test/constants.ts index 5e1fd83b..b2d00e85 100644 --- a/src/test/constants.ts +++ b/src/test/constants.ts @@ -33,6 +33,8 @@ function isMultiRootTest() { export const EXTENSION_ROOT_DIR_FOR_TESTS = path.join(__dirname, '..', '..'); export const PVSC_EXTENSION_ID_FOR_TESTS = 'ms-python.python'; +export const PVSC_ENVS_EXTENSION_ID_FOR_TESTS = 'ms-python.vscode-python-envs'; + export const SMOKE_TEST_EXTENSIONS_DIR = path.join( EXTENSION_ROOT_DIR_FOR_TESTS, 'tmp', diff --git a/src/test/runTest.ts b/src/test/runTest.ts index 4122198f..464e0042 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -2,8 +2,7 @@ import * as cp from 'child_process'; import * as path from 'path'; import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath, runTests } from '@vscode/test-electron'; -import { PVSC_EXTENSION_ID_FOR_TESTS } from './constants'; -import { OSType, getOSType } from '../extension/common/platform'; +import { PVSC_ENVS_EXTENSION_ID_FOR_TESTS, PVSC_EXTENSION_ID_FOR_TESTS } from './constants'; async function main() { try { @@ -18,19 +17,49 @@ async function main() { const [cliPath, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath); // Use cp.spawn / cp.exec for custom setup - if (getOSType() === OSType.Windows) { - const exec = path.basename(cliPath); - cp.spawnSync(exec, [...args, '--install-extension', PVSC_EXTENSION_ID_FOR_TESTS], { - cwd: path.dirname(cliPath), - encoding: 'utf-8', - stdio: 'inherit', - }); + const isWin = process.platform === 'win32'; + if (isWin) { + try { + const installResult = cp.spawnSync( + cliPath, + [...args, '--install-extension', PVSC_EXTENSION_ID_FOR_TESTS, PVSC_ENVS_EXTENSION_ID_FOR_TESTS], + { + cwd: path.dirname(cliPath), + encoding: 'utf8', + stdio: 'inherit', + shell: true, + }, + ); + if (installResult.error) { + console.error('Extension installation error:', installResult.error); + } + if (installResult.status !== 0) { + console.error(`Extension installation failed with exit code: ${installResult.status}`); + } else { + console.log('Extension installation succeeded.'); + } + } catch (ex) { + console.error('Exception during extension installation:', ex); + } } else { - cp.spawnSync(cliPath, [...args, '--install-extension', PVSC_EXTENSION_ID_FOR_TESTS], { - encoding: 'utf-8', - stdio: 'inherit', - }); + const installResult = cp.spawnSync( + cliPath, + [...args, '--install-extension', PVSC_EXTENSION_ID_FOR_TESTS, PVSC_ENVS_EXTENSION_ID_FOR_TESTS], + { + encoding: 'utf8', + stdio: 'inherit', + }, + ); + if (installResult.error) { + console.error('Extension installation error:', installResult.error); + } + if (installResult.status !== 0) { + console.error(`Extension installation failed with exit code: ${installResult.status}`); + } else { + console.log('Extension installation succeeded.'); + } } + console.log('Extensions installed, ready to run tests.'); // Run the extension test await runTests({ diff --git a/src/test/unittest/adapter/factory.unit.test.ts b/src/test/unittest/adapter/factory.unit.test.ts index 86342d2c..df17088d 100644 --- a/src/test/unittest/adapter/factory.unit.test.ts +++ b/src/test/unittest/adapter/factory.unit.test.ts @@ -11,7 +11,14 @@ import * as path from 'path'; import * as sinon from 'sinon'; import { SemVer } from 'semver'; import { instance, mock, when } from 'ts-mockito'; -import { DebugAdapterExecutable, DebugAdapterServer, DebugConfiguration, DebugSession, WorkspaceFolder } from 'vscode'; +import { + DebugAdapterExecutable, + DebugAdapterServer, + DebugConfiguration, + DebugSession, + Uri, + WorkspaceFolder, +} from 'vscode'; import { IPersistentStateFactory } from '../../../extension/common/types'; import { DebugAdapterDescriptorFactory, debugStateKeys } from '../../../extension/debugger/adapter/factory'; import { IDebugAdapterDescriptorFactory } from '../../../extension/debugger/types'; @@ -24,6 +31,7 @@ import * as telemetry from '../../../extension/telemetry'; import * as telemetryReporter from '../../../extension/telemetry/reporter'; import * as vscodeApi from '../../../extension/common/vscodeapi'; import { DebugConfigStrings } from '../../../extension/common/utils/localize'; +import { PythonEnvironment } from '../../../extension/envExtApi'; use(chaiAsPromised); @@ -33,23 +41,36 @@ suite('Debugging - Adapter Factory', () => { let state: PersistentState; let showErrorMessageStub: sinon.SinonStub; let resolveEnvironmentStub: sinon.SinonStub; - let getInterpretersStub: sinon.SinonStub; let getInterpreterDetailsStub: sinon.SinonStub; - let hasInterpretersStub: sinon.SinonStub; let getTelemetryReporterStub: sinon.SinonStub; let reporter: any; const nodeExecutable = undefined; const debugAdapterPath = path.join(EXTENSION_ROOT_DIR, 'bundled', 'libs', 'debugpy', 'adapter'); const pythonPath = 'path/to/python/interpreter'; - const interpreter = { - architecture: Architecture.Unknown, - path: pythonPath, - sysPrefix: '', - sysVersion: '', - envType: 'Unknow', - version: new SemVer('3.7.4-test'), - }; + function createInterpreter(executable: string, version: string): PythonEnvironment { + return { + envId: { id: executable, managerId: 'Venv' }, + name: `Python ${version}`, + displayName: `Python ${version}`, + displayPath: executable, + version, + environmentPath: Uri.file(executable), + execInfo: { + run: { + executable, + args: [], + }, + activatedRun: { + executable, + args: [], + }, + }, + sysPrefix: '', + }; + } + + const interpreter: PythonEnvironment = createInterpreter(pythonPath, '3.7.4-test'); const oldValueOfVSC_PYTHON_UNIT_TEST = process.env.VSC_PYTHON_UNIT_TEST; const oldValueOfVSC_PYTHON_CI_TEST = process.env.VSC_PYTHON_CI_TEST; @@ -73,16 +94,12 @@ suite('Debugging - Adapter Factory', () => { state = mock(PersistentState) as PersistentState; showErrorMessageStub = sinon.stub(vscodeApi, 'showErrorMessage'); resolveEnvironmentStub = sinon.stub(pythonApi, 'resolveEnvironment'); - getInterpretersStub = sinon.stub(pythonApi, 'getInterpreters'); getInterpreterDetailsStub = sinon.stub(pythonApi, 'getInterpreterDetails'); - hasInterpretersStub = sinon.stub(pythonApi, 'hasInterpreters'); getTelemetryReporterStub = sinon.stub(telemetryReporter, 'getTelemetryReporter'); when( stateFactory.createGlobalPersistentState(debugStateKeys.doNotShowAgain, false), ).thenReturn(instance(state)); - getInterpretersStub.returns([interpreter]); - hasInterpretersStub.returns(true); getTelemetryReporterStub.returns(reporter); factory = new DebugAdapterDescriptorFactory(instance(stateFactory)); }); @@ -122,7 +139,7 @@ suite('Debugging - Adapter Factory', () => { test('Return the path of the active interpreter as the current python path, it exists and configuration.pythonPath is not defined', async () => { const session = createSession({}); const debugExecutable = new DebugAdapterExecutable(pythonPath, [debugAdapterPath]); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); resolveEnvironmentStub.resolves(interpreter); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -141,18 +158,16 @@ suite('Debugging - Adapter Factory', () => { }); test('Display a message if python version is less than 3.7', async () => { - getInterpretersStub.returns([]); const session = createSession({}); - const deprecatedInterpreter = { + const deprecatedInterpreter: PythonEnvironment = { + ...createInterpreter(pythonPath, '3.6.12-test'), + // Provide semver-like object for version check path while keeping string version for our helper. architecture: Architecture.Unknown, - path: pythonPath, - sysPrefix: '', - sysVersion: '', - envType: 'Unknown', - version: new SemVer('3.6.12-test'), - }; + // Keep a SemVer instance separately if code relies on it (factory only parses string). + semVer: new SemVer('3.6.12-test'), + } as any; when(state.value).thenReturn(false); - getInterpreterDetailsStub.resolves({ path: [deprecatedInterpreter.path] }); + getInterpreterDetailsStub.resolves({ path: [deprecatedInterpreter.execInfo.run.executable] }); resolveEnvironmentStub.resolves(deprecatedInterpreter); await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -166,7 +181,6 @@ suite('Debugging - Adapter Factory', () => { const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); // Interpreter not needed for host/port - sinon.assert.neverCalledWith(getInterpretersStub); assert.deepStrictEqual(descriptor, debugServer); }); @@ -181,7 +195,6 @@ suite('Debugging - Adapter Factory', () => { const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); // Interpreter not needed for connect - sinon.assert.neverCalledWith(getInterpretersStub); assert.deepStrictEqual(descriptor, debugServer); }); @@ -191,14 +204,13 @@ suite('Debugging - Adapter Factory', () => { const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); // Interpreter not needed for connect - sinon.assert.neverCalledWith(getInterpretersStub); assert.deepStrictEqual(descriptor, debugServer); }); test('Return Debug Adapter executable if request is "attach", and listen is specified', async () => { const session = createSession({ request: 'attach', listen: { port: 5678, host: 'localhost' } }); const debugExecutable = new DebugAdapterExecutable(pythonPath, [debugAdapterPath]); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); resolveEnvironmentStub.resolves(interpreter); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -229,8 +241,8 @@ suite('Debugging - Adapter Factory', () => { EXTENSION_ROOT_DIR, ]); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); - resolveEnvironmentStub.withArgs(interpreter.path).resolves(interpreter); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); + resolveEnvironmentStub.withArgs(interpreter.execInfo.run.executable).resolves(interpreter); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -241,8 +253,8 @@ suite('Debugging - Adapter Factory', () => { const session = createSession({}); const debugExecutable = new DebugAdapterExecutable(pythonPath, [debugAdapterPath]); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); - resolveEnvironmentStub.withArgs(interpreter.path).resolves(interpreter); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); + resolveEnvironmentStub.withArgs(interpreter.execInfo.run.executable).resolves(interpreter); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -253,8 +265,8 @@ suite('Debugging - Adapter Factory', () => { const session = createSession({ logToFile: false }); const debugExecutable = new DebugAdapterExecutable(pythonPath, [debugAdapterPath]); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); - resolveEnvironmentStub.withArgs(interpreter.path).resolves(interpreter); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); + resolveEnvironmentStub.withArgs(interpreter.execInfo.run.executable).resolves(interpreter); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -263,8 +275,8 @@ suite('Debugging - Adapter Factory', () => { test('Send attach to local process telemetry if attaching to a local process', async () => { const session = createSession({ request: 'attach', processId: 1234 }); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); - resolveEnvironmentStub.withArgs(interpreter.path).resolves(interpreter); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); + resolveEnvironmentStub.withArgs(interpreter.execInfo.run.executable).resolves(interpreter); await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -273,8 +285,8 @@ suite('Debugging - Adapter Factory', () => { test("Don't send any telemetry if not attaching to a local process", async () => { const session = createSession({}); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); - resolveEnvironmentStub.withArgs(interpreter.path).resolves(interpreter); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); + resolveEnvironmentStub.withArgs(interpreter.execInfo.run.executable).resolves(interpreter); await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -285,8 +297,8 @@ suite('Debugging - Adapter Factory', () => { const customAdapterPath = 'custom/debug/adapter/path'; const session = createSession({ debugAdapterPath: customAdapterPath }); const debugExecutable = new DebugAdapterExecutable(pythonPath, [customAdapterPath]); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); - resolveEnvironmentStub.withArgs(interpreter.path).resolves(interpreter); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); + resolveEnvironmentStub.withArgs(interpreter.execInfo.run.executable).resolves(interpreter); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); assert.deepStrictEqual(descriptor, debugExecutable); @@ -299,14 +311,9 @@ suite('Debugging - Adapter Factory', () => { const debugExecutable = new DebugAdapterExecutable(interpreterPathSpacesQuoted, [customAdapterPath]); getInterpreterDetailsStub.resolves({ path: [interpreterPathSpaces] }); - const interpreterSpacePath = { - architecture: Architecture.Unknown, - path: interpreterPathSpaces, - sysPrefix: '', - sysVersion: '', - envType: 'Unknow', - version: new SemVer('3.7.4-test'), - }; + const interpreterSpacePath: PythonEnvironment = createInterpreter(interpreterPathSpaces, '3.7.4-test'); + // Add architecture for completeness. + (interpreterSpacePath as any).architecture = Architecture.Unknown; resolveEnvironmentStub.withArgs(interpreterPathSpaces).resolves(interpreterSpacePath); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -316,15 +323,8 @@ suite('Debugging - Adapter Factory', () => { test('Use "debugAdapterPython" when specified', async () => { const session = createSession({ debugAdapterPython: '/bin/custompy' }); const debugExecutable = new DebugAdapterExecutable('/bin/custompy', [debugAdapterPath]); - const customInterpreter = { - architecture: Architecture.Unknown, - path: '/bin/custompy', - sysPrefix: '', - sysVersion: '', - envType: 'unknow', - version: new SemVer('3.7.4-test'), - }; - + const customInterpreter: PythonEnvironment = createInterpreter('/bin/custompy', '3.7.4-test'); + (customInterpreter as any).architecture = Architecture.Unknown; resolveEnvironmentStub.withArgs('/bin/custompy').resolves(customInterpreter); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); @@ -334,8 +334,8 @@ suite('Debugging - Adapter Factory', () => { test('Do not use "python" to spawn the debug adapter', async () => { const session = createSession({ python: '/bin/custompy' }); const debugExecutable = new DebugAdapterExecutable(pythonPath, [debugAdapterPath]); - getInterpreterDetailsStub.resolves({ path: [interpreter.path] }); - resolveEnvironmentStub.withArgs(interpreter.path).resolves(interpreter); + getInterpreterDetailsStub.resolves({ path: [interpreter.execInfo.run.executable] }); + resolveEnvironmentStub.withArgs(interpreter.execInfo.run.executable).resolves(interpreter); const descriptor = await factory.createDebugAdapterDescriptor(session, nodeExecutable); assert.deepStrictEqual(descriptor, debugExecutable); diff --git a/src/test/unittest/common/application/commands/reportIssueCommand.unit.test.ts b/src/test/unittest/common/application/commands/reportIssueCommand.unit.test.ts index 1434d718..cc954842 100644 --- a/src/test/unittest/common/application/commands/reportIssueCommand.unit.test.ts +++ b/src/test/unittest/common/application/commands/reportIssueCommand.unit.test.ts @@ -14,7 +14,7 @@ import * as vscodeapi from '../../../../../extension/common/vscodeapi'; import * as pythonApi from '../../../../../extension/common/python'; import { EXTENSION_ROOT_DIR_FOR_TESTS } from '../../../../constants'; import { openReportIssue } from '../../../../../extension/common/application/commands/reportIssueCommand'; -import { PythonEnvironment } from '../../../../../extension/debugger/adapter/types'; +import { PythonEnvironment } from '../../../../../extension/envExtApi'; suite('Report Issue Command', () => { let executeCommandStub: sinon.SinonStub; @@ -23,21 +23,21 @@ suite('Report Issue Command', () => { setup(async () => { executeCommandStub = sinon.stub(vscodeapi, 'executeCommand'); resolveEnvironmentStub = sinon.stub(pythonApi, 'resolveEnvironment'); + // Ensure useEnvironmentsExtension is false for these tests + (pythonApi as any).useEnvironmentsExtension = false; const interpreter = { - environment: { - type: 'Venv', - }, - version: { - major: 3, - minor: 9, - micro: 0, + envId: { + id: '/path/to/interpreter', + managerId: 'Venv', }, + version: '3.9.0', } as unknown as PythonEnvironment; resolveEnvironmentStub.resolves(interpreter); }); teardown(() => { sinon.restore(); + (pythonApi as any).useEnvironmentsExtension = undefined; }); test('Test if issue body is filled correctly when including all the settings', async () => { diff --git a/src/test/unittest/common/helpers.ts b/src/test/unittest/common/helpers.ts new file mode 100644 index 00000000..6ce8d848 --- /dev/null +++ b/src/test/unittest/common/helpers.ts @@ -0,0 +1,30 @@ +import { Uri } from 'vscode'; +import { PythonEnvironment } from '../../../extension/envExtApi'; + +/** + * Helper to build a simple PythonEnvironment object for tests. + * @param execPath string - path to the python executable + * @param version string - python version string (e.g. '3.9.0') + * @param sysPrefix string - sysPrefix value (optional) + */ +export function buildPythonEnvironment(execPath: string, version: string, sysPrefix: string = ''): PythonEnvironment { + const execUri = Uri.file(execPath); + return { + envId: { + id: execUri.fsPath, + managerId: 'Venv', + }, + name: `Python ${version}`, + displayName: `Python ${version}`, + displayPath: execUri.fsPath, + version: version, + environmentPath: execUri, + execInfo: { + run: { + executable: execUri.fsPath, + args: [], + }, + }, + sysPrefix, + } as PythonEnvironment; +} diff --git a/src/test/unittest/common/python.unit.test.ts b/src/test/unittest/common/python.unit.test.ts new file mode 100644 index 00000000..be94ea23 --- /dev/null +++ b/src/test/unittest/common/python.unit.test.ts @@ -0,0 +1,617 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import { expect } from 'chai'; +import * as sinon from 'sinon'; +import { Uri, Disposable, Extension, commands, extensions } from 'vscode'; +import * as pythonApi from '../../../extension/common/python'; +import { + PythonExtension, + Environment, + EnvironmentPath, + ResolvedEnvironment, + ActiveEnvironmentPathChangeEvent, +} from '@vscode/python-extension'; + +suite('Python API Tests', () => { + let getExtensionStub: sinon.SinonStub; + let executeCommandStub: sinon.SinonStub; + let mockPythonExtension: Extension; + let mockEnvsExtension: Extension; + let mockPythonExtensionApi: any; + let mockPythonEnvApi: any; + + setup(() => { + // Stub extensions.getExtension + getExtensionStub = sinon.stub(extensions, 'getExtension'); + executeCommandStub = sinon.stub(commands, 'executeCommand'); + + // Create mock Python extension + mockPythonExtension = { + id: 'ms-python.python', + extensionUri: Uri.file('/mock/path'), + extensionPath: '/mock/path', + isActive: true, + packageJSON: {}, + exports: undefined, + activate: sinon.stub().resolves(), + extensionKind: 1, + } as any; + + // Create mock Python Envs extension + mockEnvsExtension = { + id: 'ms-python.vscode-python-envs', + extensionUri: Uri.file('/mock/path'), + extensionPath: '/mock/path', + isActive: true, + packageJSON: {}, + exports: undefined, + activate: sinon.stub().resolves(), + extensionKind: 1, + } as any; + + // Create mock Python extension API + mockPythonExtensionApi = { + ready: Promise.resolve(), + settings: { + getExecutionDetails: sinon.stub().returns({ execCommand: undefined }), + }, + }; + + // Create mock Python environment API + mockPythonEnvApi = { + environments: { + known: [], + getActiveEnvironmentPath: sinon.stub(), + resolveEnvironment: sinon.stub(), + getEnvironmentVariables: sinon.stub(), + onDidChangeActiveEnvironmentPath: sinon.stub().returns({ dispose: sinon.stub() }), + onDidChangeEnvironments: sinon.stub().returns({ dispose: sinon.stub() }), + refreshEnvironments: sinon.stub().resolves(), + }, + }; + + // Setup default behavior + getExtensionStub.withArgs('ms-python.python').returns(mockPythonExtension); + getExtensionStub.withArgs('ms-python.vscode-python-envs').returns(mockEnvsExtension); + }); + + teardown(() => { + sinon.restore(); + }); + + suite('initializePython', () => { + test('Should initialize python and set up event listeners', async () => { + const disposables: Disposable[] = []; + + (mockPythonExtension as any).exports = mockPythonExtensionApi; + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath.returns({ + dispose: sinon.stub(), + }); + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + // Stub PythonExtension.api() + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + await pythonApi.initializePython(disposables); + + expect(disposables.length).to.be.greaterThan(0); + expect(mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath.called).to.be.true; + }); + + test('Should handle errors gracefully when python extension is not available', async () => { + const disposables: Disposable[] = []; + sinon.stub(PythonExtension, 'api').rejects(new Error('Extension not found')); + + await pythonApi.initializePython(disposables); + + // Should not throw, just handle error internally + expect(disposables.length).to.equal(0); + }); + + test('Should fire onDidChangePythonInterpreter event after initialization', async () => { + const disposables: Disposable[] = []; + const mockEventHandler = sinon.stub(); + + (mockPythonExtension as any).exports = mockPythonExtensionApi; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Event should be fired during initialization + sinon.assert.called(mockEventHandler); + }); + }); + + suite('runPythonExtensionCommand', () => { + test('Should execute command through VS Code commands API', async () => { + (mockPythonExtension as any).isActive = true; + executeCommandStub.resolves('result'); + + const result = await pythonApi.runPythonExtensionCommand('python.test.command', 'arg1', 'arg2'); + + expect(result).to.equal('result'); + sinon.assert.calledWith(executeCommandStub, 'python.test.command', 'arg1', 'arg2'); + }); + + test('Should activate extension before executing command if not active', async () => { + (mockPythonExtension as any).isActive = false; + const activateStub = mockPythonExtension.activate as sinon.SinonStub; + executeCommandStub.resolves('result'); + + await pythonApi.runPythonExtensionCommand('python.test.command'); + + sinon.assert.called(activateStub); + sinon.assert.called(executeCommandStub); + }); + }); + + suite('getSettingsPythonPath', () => { + test('Should return execution details from Python extension API', async () => { + const expectedPath = ['/usr/bin/python3']; + mockPythonExtensionApi.settings.getExecutionDetails.returns({ execCommand: expectedPath }); + (mockPythonExtension as any).exports = mockPythonExtensionApi; + (mockPythonExtension as any).isActive = true; + + const result = await pythonApi.getSettingsPythonPath(); + + expect(result).to.deep.equal(expectedPath); + }); + + test('Should return execution details for specific resource', async () => { + const resource = Uri.file('/workspace/file.py'); + const expectedPath = ['/usr/bin/python3']; + mockPythonExtensionApi.settings.getExecutionDetails.returns({ execCommand: expectedPath }); + (mockPythonExtension as any).exports = mockPythonExtensionApi; + (mockPythonExtension as any).isActive = true; + + const result = await pythonApi.getSettingsPythonPath(resource); + + expect(result).to.deep.equal(expectedPath); + sinon.assert.calledWith(mockPythonExtensionApi.settings.getExecutionDetails, resource); + }); + + test('Should return undefined when execCommand is not available', async () => { + mockPythonExtensionApi.settings.getExecutionDetails.returns({ execCommand: undefined }); + (mockPythonExtension as any).exports = mockPythonExtensionApi; + (mockPythonExtension as any).isActive = true; + + const result = await pythonApi.getSettingsPythonPath(); + + expect(result).to.be.undefined; + }); + }); + + suite('getEnvironmentVariables', () => { + test('Should return environment variables from Python extension API', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: '/usr/bin', PYTHONPATH: '/usr/lib/python3' }; + mockPythonEnvApi.environments.getEnvironmentVariables.returns(Promise.resolve(expectedVars)); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getEnvironmentVariables(); + + expect(result).to.deep.equal(expectedVars); + sinon.assert.calledWith(mockPythonEnvApi.environments.getEnvironmentVariables, sinon.match.any); + }); + + test('Should get environment variables for specific resource', async () => { + const resource = Uri.file('/workspace/file.py'); + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: '/usr/bin' }; + mockPythonEnvApi.environments.getEnvironmentVariables.returns(Promise.resolve(expectedVars)); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getEnvironmentVariables(resource); + + expect(result).to.deep.equal(expectedVars); + sinon.assert.calledWith(mockPythonEnvApi.environments.getEnvironmentVariables, resource); + }); + + test('Should handle undefined resource and return workspace environment variables', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: '/usr/bin', PYTHONPATH: '/workspace/python' }; + mockPythonEnvApi.environments.getEnvironmentVariables.returns(Promise.resolve(expectedVars)); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getEnvironmentVariables(undefined); + + expect(result).to.deep.equal(expectedVars); + sinon.assert.calledWith(mockPythonEnvApi.environments.getEnvironmentVariables, undefined); + }); + }); + + suite('resolveEnvironment', () => { + test('Should resolve environment from path string', async () => { + const envPath = '/usr/bin/python3'; + // Legacy branch returns a PythonEnvironment shape, not the minimal ResolvedEnvironment. + // Assert critical fields instead of deep equality with a minimal object. + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + id: 'test-env', + executable: { uri: Uri.file(envPath) }, + }); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.resolveEnvironment(envPath); + expect(result).to.not.be.undefined; + // PythonEnvironment generated by legacyResolveEnvironment -> converted shape + const expectedPath = Uri.file(envPath).fsPath; + expect((result as any).execInfo?.run?.executable).to.equal(expectedPath); + expect((result as any).environmentPath?.fsPath).to.equal(expectedPath); + expect((result as any).displayPath).to.equal(expectedPath); + expect((result as any).version).to.equal('Unknown'); + }); + + test('Should resolve environment from Environment object', async () => { + const env: Environment = { + id: 'test-env', + path: '/usr/bin/python3', + } as Environment; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + id: 'test-env', + executable: { uri: Uri.file('/usr/bin/python3') }, + }); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.resolveEnvironment(env); + expect(result).to.not.be.undefined; + const expectedPath = Uri.file('/usr/bin/python3').fsPath; + expect((result as any).execInfo?.run?.executable).to.equal(expectedPath); + expect((result as any).environmentPath?.fsPath).to.equal(expectedPath); + expect((result as any).displayPath).to.equal(expectedPath); + }); + + test('Should return undefined for invalid environment', async () => { + const envPath = '/invalid/path'; + mockPythonEnvApi.environments.resolveEnvironment.resolves(undefined); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.resolveEnvironment(envPath); + + expect(result).to.be.undefined; + }); + }); + + suite('getActiveEnvironmentPath', () => { + test('Should return active environment path', async () => { + const expectedPath: EnvironmentPath = { + id: 'test-env', + path: '/usr/bin/python3', + }; + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns(expectedPath); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getActiveEnvironmentPath(); + + expect(result).to.deep.equal(expectedPath); + }); + + test('Should return active environment path for specific resource', async () => { + const resource = Uri.file('/workspace/file.py'); + const expectedPath: EnvironmentPath = { + id: 'test-env', + path: '/usr/bin/python3', + }; + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns(expectedPath); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getActiveEnvironmentPath(resource); + + expect(result).to.deep.equal(expectedPath); + sinon.assert.calledWith(mockPythonEnvApi.environments.getActiveEnvironmentPath, resource); + }); + }); + + suite('getInterpreterDetails', () => { + test('Should return interpreter details with path', async () => { + const pythonPath = '/usr/bin/python3'; + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: Uri.file(pythonPath) }, + } as ResolvedEnvironment; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: pythonPath }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + // Use Uri.file().fsPath to get platform-normalized path for comparison + expect(result.path).to.deep.equal([Uri.file(pythonPath).fsPath]); + expect(result.resource).to.be.undefined; + }); + + test('Should return interpreter details with resource', async () => { + const resource = Uri.file('/workspace/file.py'); + const pythonPath = '/usr/bin/python3'; + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: Uri.file(pythonPath) }, + } as ResolvedEnvironment; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: pythonPath }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(resource); + + // Use Uri.file().fsPath to get platform-normalized path for comparison + expect(result.path).to.deep.equal([Uri.file(pythonPath).fsPath]); + expect(result.resource).to.deep.equal(resource); + }); + + test('Should not quote path with spaces', async () => { + // this should be updated when we fix the quoting logic in getInterpreterDetails + const pythonPath = '/path with spaces/python3'; + const mockUri = { + fsPath: pythonPath, + }; + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: mockUri }, + } as ResolvedEnvironment; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: pythonPath }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.deep.equal([`${pythonPath}`]); + }); + + test('Should not double-quote already quoted path', async () => { + const quotedPythonPath = '"/path with spaces/python3"'; + // Create a mock Uri that when accessed via fsPath returns the already quoted path + const mockUri = { + fsPath: quotedPythonPath, + } as Uri; + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: mockUri }, + } as ResolvedEnvironment; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: quotedPythonPath }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.deep.equal([quotedPythonPath]); + }); + + test('Should return undefined path when environment is not resolved', async () => { + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: '/usr/bin/python3' }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(undefined); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.be.undefined; + expect(result.resource).to.be.undefined; + }); + + test('Should return undefined path when executable uri is not available', async () => { + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: undefined }, + } as any; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: '/usr/bin/python3' }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.be.undefined; + }); + }); + + suite('onDidChangePythonInterpreter event', () => { + test('Should fire event when active environment path changes', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change + const changeEvent: ActiveEnvironmentPathChangeEvent = { + id: 'test-env', + path: '/usr/bin/python3.9', + resource: Uri.file('/workspace'), + }; + eventCallback(changeEvent); + + // Should be called at least twice: once during init, once from the event + expect(mockEventHandler.callCount).to.be.greaterThan(1); + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal(['/usr/bin/python3.9']); + expect(lastCall.resource).to.deep.equal(Uri.file('/workspace')); + }); + + test('Should handle WorkspaceFolder resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with WorkspaceFolder resource + const workspaceFolderUri = Uri.file('/workspace'); + const changeEvent: any = { + id: 'test-env', + path: '/usr/bin/python3.9', + resource: { uri: workspaceFolderUri, name: 'workspace', index: 0 }, + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.resource).to.deep.equal(workspaceFolderUri); + }); + + test('Should handle null resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with null resource + const changeEvent: any = { + id: 'test-env', + path: '/usr/bin/python3.9', + resource: null, + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal(['/usr/bin/python3.9']); + expect(lastCall.resource).to.be.undefined; // null gets converted to undefined + }); + + test('Should handle undefined resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with undefined resource + const changeEvent: ActiveEnvironmentPathChangeEvent = { + id: 'test-env', + path: '/usr/bin/python3.9', + resource: undefined, + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal(['/usr/bin/python3.9']); + expect(lastCall.resource).to.be.undefined; + }); + + test('Should handle event with missing id', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with missing id + const changeEvent: any = { + path: '/usr/bin/python3.9', + resource: Uri.file('/workspace'), + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal(['/usr/bin/python3.9']); + expect(lastCall.resource).to.deep.equal(Uri.file('/workspace')); + }); + + test('Should handle event with null path', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with null path + const changeEvent: any = { + id: 'test-env', + path: null, + resource: Uri.file('/workspace'), + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal([null]); + expect(lastCall.resource).to.deep.equal(Uri.file('/workspace')); + }); + }); +}); diff --git a/src/test/unittest/common/pythonFalse.unit.test.ts b/src/test/unittest/common/pythonFalse.unit.test.ts new file mode 100644 index 00000000..f5ff31ee --- /dev/null +++ b/src/test/unittest/common/pythonFalse.unit.test.ts @@ -0,0 +1,619 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { expect } from 'chai'; +import * as sinon from 'sinon'; +import { Uri, Disposable, Extension, commands, extensions } from 'vscode'; +import * as pythonApi from '../../../extension/common/python'; +import * as utilities from '../../../extension/common/utilities'; +import { + PythonExtension, + Environment, + EnvironmentPath, + ResolvedEnvironment, + ActiveEnvironmentPathChangeEvent, +} from '@vscode/python-extension'; +import { buildPythonEnvironment } from './helpers'; + +suite('Python API Tests - useEnvironmentsExtension:false', () => { + let getExtensionStub: sinon.SinonStub; + let executeCommandStub: sinon.SinonStub; + let mockPythonExtension: Extension; + let mockEnvsExtension: Extension; + let mockPythonExtensionApi: any; + let mockPythonEnvApi: any; + + setup(() => { + // Stub extensions.getExtension + getExtensionStub = sinon.stub(extensions, 'getExtension'); + executeCommandStub = sinon.stub(commands, 'executeCommand'); + + // Mock useEnvExtension to return false for this test suite + sinon.stub(utilities, 'useEnvExtension').returns(false); + + // Create mock Python extension + mockPythonExtension = { + id: 'ms-python.python', + extensionUri: Uri.file('/mock/path'), + extensionPath: '/mock/path', + isActive: true, + packageJSON: {}, + exports: undefined, + activate: sinon.stub().resolves(), + extensionKind: 1, + } as any; + + // Create mock Python Envs extension + mockEnvsExtension = { + id: 'ms-python.vscode-python-envs', + extensionUri: Uri.file('/mock/path'), + extensionPath: '/mock/path', + isActive: true, + packageJSON: {}, + exports: undefined, + activate: sinon.stub().resolves(), + extensionKind: 1, + } as any; + + // Create mock Python extension API + mockPythonExtensionApi = { + ready: Promise.resolve(), + settings: { + getExecutionDetails: sinon.stub().returns({ execCommand: undefined }), + }, + }; + + // Create mock Python environment API + mockPythonEnvApi = { + environments: { + known: [], + getActiveEnvironmentPath: sinon.stub(), + resolveEnvironment: sinon.stub(), + getEnvironmentVariables: sinon.stub(), + onDidChangeActiveEnvironmentPath: sinon.stub().returns({ dispose: sinon.stub() }), + onDidChangeEnvironments: sinon.stub().returns({ dispose: sinon.stub() }), + refreshEnvironments: sinon.stub().resolves(), + }, + }; + + // Setup default behavior + getExtensionStub.withArgs('ms-python.python').returns(mockPythonExtension); + getExtensionStub.withArgs('ms-python.vscode-python-envs').returns(mockEnvsExtension); + (pythonApi as any)._useExt = false; + }); + + teardown(() => { + sinon.restore(); + // Reset useEnvironmentsExtension after each test + (pythonApi as any)._useExt = undefined; + }); + + suite('initializePython', () => { + test('Should initialize python and set up event listeners', async () => { + const disposables: Disposable[] = []; + (mockPythonExtension as any).exports = mockPythonExtensionApi; + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath.returns({ + dispose: sinon.stub(), + }); + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + // Stub PythonExtension.api() + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + await pythonApi.initializePython(disposables); + expect(disposables.length).to.be.greaterThan(0); + expect(mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath.called).to.be.true; + }); + + test('Should handle errors gracefully when python extension is not available', async () => { + const disposables: Disposable[] = []; + sinon.stub(PythonExtension, 'api').rejects(new Error('Extension not found')); + + await pythonApi.initializePython(disposables); + + // Should not throw, just handle error internally + expect(disposables.length).to.equal(0); + }); + + test('Should fire onDidChangePythonInterpreter event after initialization', async () => { + const disposables: Disposable[] = []; + const mockEventHandler = sinon.stub(); + + (mockPythonExtension as any).exports = mockPythonExtensionApi; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Event should be fired during initialization + sinon.assert.called(mockEventHandler); + }); + }); + + suite('runPythonExtensionCommand', () => { + test('Should execute command through VS Code commands API', async () => { + (mockPythonExtension as any).isActive = true; + executeCommandStub.resolves('result'); + + const result = await pythonApi.runPythonExtensionCommand('python.test.command', 'arg1', 'arg2'); + + expect(result).to.equal('result'); + sinon.assert.calledWith(executeCommandStub, 'python.test.command', 'arg1', 'arg2'); + }); + + test('Should activate extension before executing command if not active', async () => { + (mockPythonExtension as any).isActive = false; + const activateStub = mockPythonExtension.activate as sinon.SinonStub; + executeCommandStub.resolves('result'); + + await pythonApi.runPythonExtensionCommand('python.test.command'); + + sinon.assert.called(activateStub); + sinon.assert.called(executeCommandStub); + }); + }); + + suite('getSettingsPythonPath', () => { + test('Should return execution details from Python extension API', async () => { + const expectedPath = ['/usr/bin/python3']; + mockPythonExtensionApi.settings.getExecutionDetails.returns({ execCommand: expectedPath }); + (mockPythonExtension as any).exports = mockPythonExtensionApi; + (mockPythonExtension as any).isActive = true; + + const result = await pythonApi.getSettingsPythonPath(); + + expect(result).to.deep.equal(expectedPath); + }); + + test('Should return execution details for specific resource', async () => { + const resource = Uri.file('/workspace/file.py'); + const expectedPath = ['/usr/bin/python3']; + mockPythonExtensionApi.settings.getExecutionDetails.returns({ execCommand: expectedPath }); + (mockPythonExtension as any).exports = mockPythonExtensionApi; + (mockPythonExtension as any).isActive = true; + + const result = await pythonApi.getSettingsPythonPath(resource); + + expect(result).to.deep.equal(expectedPath); + sinon.assert.calledWith(mockPythonExtensionApi.settings.getExecutionDetails, resource); + }); + + test('Should return undefined when execCommand is not available', async () => { + mockPythonExtensionApi.settings.getExecutionDetails.returns({ execCommand: undefined }); + (mockPythonExtension as any).exports = mockPythonExtensionApi; + (mockPythonExtension as any).isActive = true; + + const result = await pythonApi.getSettingsPythonPath(); + + expect(result).to.be.undefined; + }); + }); + + suite('getEnvironmentVariables', () => { + test('Should return environment variables from Python extension API', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: '/usr/bin', PYTHONPATH: '/usr/lib/python3' }; + mockPythonEnvApi.environments.getEnvironmentVariables.returns(Promise.resolve(expectedVars)); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getEnvironmentVariables(); + + expect(result).to.deep.equal(expectedVars); + sinon.assert.calledWith(mockPythonEnvApi.environments.getEnvironmentVariables, sinon.match.any); + }); + + test('Should get environment variables for specific resource', async () => { + const resource = Uri.file('/workspace/file.py'); + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: '/usr/bin' }; + mockPythonEnvApi.environments.getEnvironmentVariables.returns(Promise.resolve(expectedVars)); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getEnvironmentVariables(resource); + + expect(result).to.deep.equal(expectedVars); + sinon.assert.calledWith(mockPythonEnvApi.environments.getEnvironmentVariables, resource); + }); + + test('Should handle undefined resource and return workspace environment variables', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: '/usr/bin', PYTHONPATH: '/workspace/python' }; + mockPythonEnvApi.environments.getEnvironmentVariables.returns(Promise.resolve(expectedVars)); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getEnvironmentVariables(undefined); + + expect(result).to.deep.equal(expectedVars); + sinon.assert.calledWith(mockPythonEnvApi.environments.getEnvironmentVariables, undefined); + }); + }); + + suite('resolveEnvironment', () => { + test('Should resolve environment from path string', async () => { + const envPath = '/usr/bin/python3'; + const mockResolvedEnv: ResolvedEnvironment = { + id: 'test-env', + version: { major: 3, minor: 9, micro: 0 }, + executable: { uri: Uri.file(envPath) }, + } as ResolvedEnvironment; + const expectedEnv = buildPythonEnvironment(envPath, '3.9.0'); + + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockResolvedEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.resolveEnvironment(envPath); + + expect(result).to.deep.equal(expectedEnv); + sinon.assert.calledWith(mockPythonEnvApi.environments.resolveEnvironment, envPath); + }); + + test('Should resolve environment from Environment object', async () => { + let pythonPath = '/usr/bin/python3'; + const env: Environment = { + id: 'test-env', + path: pythonPath, + } as Environment; + const mockResolvedEnv: ResolvedEnvironment = { + id: 'test-env', + version: { major: 3, minor: 9, micro: 0 }, + executable: { uri: Uri.file(pythonPath) }, + } as ResolvedEnvironment; + const expectedEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockResolvedEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.resolveEnvironment(env); + + expect(result).to.deep.equal(expectedEnv); + }); + + test('Should return undefined for invalid environment', async () => { + const envPath = '/invalid/path'; + mockPythonEnvApi.environments.resolveEnvironment.resolves(undefined); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.resolveEnvironment(envPath); + + expect(result).to.be.undefined; + }); + }); + + suite('getActiveEnvironmentPath', () => { + test('Should return active environment path', async () => { + const expectedPath: EnvironmentPath = { + id: 'test-env', + path: '/usr/bin/python3', + }; + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns(expectedPath); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getActiveEnvironmentPath(); + + expect(result).to.deep.equal(expectedPath); + }); + + test('Should return active environment path for specific resource', async () => { + const resource = Uri.file('/workspace/file.py'); + const expectedPath: EnvironmentPath = { + id: 'test-env', + path: '/usr/bin/python3', + }; + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns(expectedPath); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getActiveEnvironmentPath(resource); + + expect(result).to.deep.equal(expectedPath); + sinon.assert.calledWith(mockPythonEnvApi.environments.getActiveEnvironmentPath, resource); + }); + }); + + suite('getInterpreterDetails', () => { + test('Should return interpreter details with path', async () => { + const pythonPath = '/usr/bin/python3'; + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: Uri.file(pythonPath) }, + } as ResolvedEnvironment; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: pythonPath }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + // Use Uri.file().fsPath to get platform-normalized path for comparison + expect(result.path).to.deep.equal([Uri.file(pythonPath).fsPath]); + expect(result.resource).to.be.undefined; + }); + + test('Should return interpreter details with resource', async () => { + const resource = Uri.file('/workspace/file.py'); + const pythonPath = '/usr/bin/python3'; + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: Uri.file(pythonPath) }, + } as ResolvedEnvironment; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: pythonPath }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(resource); + + // Use Uri.file().fsPath to get platform-normalized path for comparison + expect(result.path).to.deep.equal([Uri.file(pythonPath).fsPath]); + expect(result.resource).to.deep.equal(resource); + }); + + test('Should not quote path with spaces', async () => { + // this should be updated when we fix the quoting logic in getInterpreterDetails + const pythonPath = '/path with spaces/python3'; + const mockUri = { + fsPath: pythonPath, + }; + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: mockUri }, + } as ResolvedEnvironment; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: pythonPath }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.deep.equal([`${pythonPath}`]); + }); + + test('Should not double-quote already quoted path', async () => { + const quotedPythonPath = '"/path with spaces/python3"'; + // Create a mock Uri that when accessed via fsPath returns the already quoted path + const mockUri = { + fsPath: quotedPythonPath, + } as Uri; + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: mockUri }, + } as ResolvedEnvironment; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: quotedPythonPath }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.deep.equal([quotedPythonPath]); + }); + + test('Should return undefined path when environment is not resolved', async () => { + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: '/usr/bin/python3' }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(undefined); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.be.undefined; + expect(result.resource).to.be.undefined; + }); + + test('Should return undefined path when executable uri is not available', async () => { + const mockEnv: ResolvedEnvironment = { + id: 'test-env', + executable: { uri: undefined }, + } as any; + + mockPythonEnvApi.environments.getActiveEnvironmentPath.returns({ path: '/usr/bin/python3' }); + mockPythonEnvApi.environments.resolveEnvironment.resolves(mockEnv); + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.be.undefined; + }); + }); + + suite('onDidChangePythonInterpreter event', () => { + test('Should fire event when active environment path changes', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change + const changeEvent: ActiveEnvironmentPathChangeEvent = { + id: 'test-env', + path: '/usr/bin/python3.9', + resource: Uri.file('/workspace'), + }; + eventCallback(changeEvent); + + // Should be called at least twice: once during init, once from the event + expect(mockEventHandler.callCount).to.be.greaterThan(1); + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal(['/usr/bin/python3.9']); + expect(lastCall.resource).to.deep.equal(Uri.file('/workspace')); + }); + + test('Should handle WorkspaceFolder resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with WorkspaceFolder resource + const workspaceFolderUri = Uri.file('/workspace'); + const changeEvent: any = { + id: 'test-env', + path: '/usr/bin/python3.9', + resource: { uri: workspaceFolderUri, name: 'workspace', index: 0 }, + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.resource).to.deep.equal(workspaceFolderUri); + }); + + test('Should handle null resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with null resource + const changeEvent: any = { + id: 'test-env', + path: '/usr/bin/python3.9', + resource: null, + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal(['/usr/bin/python3.9']); + expect(lastCall.resource).to.be.undefined; // null gets converted to undefined + }); + + test('Should handle undefined resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with undefined resource + const changeEvent: ActiveEnvironmentPathChangeEvent = { + id: 'test-env', + path: '/usr/bin/python3.9', + resource: undefined, + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal(['/usr/bin/python3.9']); + expect(lastCall.resource).to.be.undefined; + }); + + test('Should handle event with missing id', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with missing id + const changeEvent: any = { + path: '/usr/bin/python3.9', + resource: Uri.file('/workspace'), + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal(['/usr/bin/python3.9']); + expect(lastCall.resource).to.deep.equal(Uri.file('/workspace')); + }); + + test('Should handle event with null path', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + mockPythonEnvApi.environments.onDidChangeActiveEnvironmentPath = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + mockPythonEnvApi.environments.resolveEnvironment.resolves({ + executable: { uri: Uri.file('/usr/bin/python3') }, + } as ResolvedEnvironment); + + sinon.stub(PythonExtension, 'api').resolves(mockPythonEnvApi); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Simulate environment path change with null path + const changeEvent: any = { + id: 'test-env', + path: null, + resource: Uri.file('/workspace'), + }; + eventCallback(changeEvent); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal([null]); + expect(lastCall.resource).to.deep.equal(Uri.file('/workspace')); + }); + }); +}); diff --git a/src/test/unittest/common/pythonTrue.unit.test.ts b/src/test/unittest/common/pythonTrue.unit.test.ts new file mode 100644 index 00000000..cccb587e --- /dev/null +++ b/src/test/unittest/common/pythonTrue.unit.test.ts @@ -0,0 +1,554 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import { expect } from 'chai'; +import * as sinon from 'sinon'; +import { Uri, Disposable, Extension, extensions } from 'vscode'; +import * as path from 'path'; +import * as pythonApi from '../../../extension/common/python'; +import * as utilities from '../../../extension/common/utilities'; +import { buildPythonEnvironment } from './helpers'; + +// Platform-specific path constants using path.join so tests assert using native separators. +// Leading root '/' preserved; on Windows this yields a leading backslash (e.g. '\\usr\\bin'). +const PYTHON_PATH = path.join('/', 'usr', 'bin', 'python3'); +const PYTHON_PATH_39 = path.join('/', 'usr', 'bin', 'python3.9'); +const PYTHON_PATH_WITH_SPACES = path.join('/', 'path with spaces', 'python3'); +const QUOTED_PYTHON_PATH = `"${PYTHON_PATH_WITH_SPACES}"`; +const PYTHON_PATH_DIR = path.join('/', 'usr', 'bin'); +const PYTHON_LIB_PYTHON3_DIR = path.join('/', 'usr', 'lib', 'python3'); +const WORKSPACE_FILE = path.join('/', 'workspace', 'file.py'); +const WORKSPACE_PYTHON_DIR = path.join('/', 'workspace', 'python'); +const INVALID_PATH = path.join('/', 'invalid', 'path'); +const MOCK_PATH = path.join('/', 'mock', 'path'); + +suite('Python API Tests- useEnvironmentsExtension:true', () => { + let getExtensionStub: sinon.SinonStub; + let mockPythonExtension: Extension; + let mockEnvsExtension: Extension; + let mockPythonEnvApi: any; + + setup(() => { + // Stub extensions.getExtension + getExtensionStub = sinon.stub(extensions, 'getExtension'); + + // Mock useEnvExtension to return true for this test suite + sinon.stub(utilities, 'useEnvExtension').returns(true); + + // Create mock Python extension + mockPythonExtension = { + id: 'ms-python.python', + extensionUri: Uri.file(MOCK_PATH), + extensionPath: MOCK_PATH, + isActive: true, + packageJSON: {}, + exports: undefined, + activate: sinon.stub().resolves(), + extensionKind: 1, + } as any; + + // Create mock Python Envs extension + mockEnvsExtension = { + id: 'ms-python.vscode-python-envs', + extensionUri: Uri.file(MOCK_PATH), + extensionPath: MOCK_PATH, + isActive: true, + packageJSON: {}, + exports: undefined, + activate: sinon.stub().resolves(), + extensionKind: 1, + } as any; + + // Create mock Python environment API - for new environments extension + mockPythonEnvApi = { + getEnvironment: sinon.stub(), + setEnvironment: sinon.stub(), + resolveEnvironment: sinon.stub(), + getEnvironmentVariables: sinon.stub(), + onDidChangeEnvironment: sinon.stub().returns({ dispose: sinon.stub() }), + onDidChangeEnvironments: sinon.stub().returns({ dispose: sinon.stub() }), + refreshEnvironments: sinon.stub().resolves(), + getEnvironments: sinon.stub(), + }; + + // Setup default behavior + getExtensionStub.withArgs('ms-python.python').returns(mockPythonExtension); + getExtensionStub.withArgs('ms-python.vscode-python-envs').returns(mockEnvsExtension); + }); + + teardown(() => { + sinon.restore(); + }); + + suite('initializePython', () => { + test('Should initialize python and set up event listeners', async () => { + const disposables: Disposable[] = []; + (mockEnvsExtension as any).exports = mockPythonEnvApi; + const mockPythonEnv = buildPythonEnvironment(PYTHON_PATH, '3.9.0'); + mockPythonEnvApi.getEnvironment.resolves(mockPythonEnv); + mockPythonEnvApi.resolveEnvironment.resolves(mockPythonEnv); + mockPythonEnvApi.onDidChangeEnvironments.returns({ + dispose: sinon.stub(), + }); + + await pythonApi.initializePython(disposables); + expect(disposables.length).to.be.greaterThan(0); + expect(mockPythonEnvApi.onDidChangeEnvironments.called).to.be.true; + }); + + test('Should handle errors gracefully when python extension is not available', async () => { + const disposables: Disposable[] = []; + // Return undefined extension to simulate extension not found + getExtensionStub.withArgs('ms-python.vscode-python-envs').returns(undefined); + + await pythonApi.initializePython(disposables); + + // Should not throw, just handle error internally + expect(disposables.length).to.equal(0); + }); + + test('Should fire onDidChangePythonInterpreter event after initialization', async () => { + const disposables: Disposable[] = []; + const mockEventHandler = sinon.stub(); + + (mockEnvsExtension as any).exports = mockPythonEnvApi; + const mockPythonEnv = buildPythonEnvironment(PYTHON_PATH, '3.9.0'); + mockPythonEnvApi.getEnvironment.resolves(mockPythonEnv); + mockPythonEnvApi.resolveEnvironment.resolves(mockPythonEnv); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Event should be fired during initialization + sinon.assert.called(mockEventHandler); + }); + }); + + suite('getSettingsPythonPath', () => { + test('Should return execution details from Python extension API', async () => { + const expectedPath = [PYTHON_PATH]; + // OLD API: Using getEnvironment() + resolveEnvironment() instead of settings.getExecutionDetails + const mockPythonEnv = buildPythonEnvironment(PYTHON_PATH, '3.9.0'); + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.resolves(mockPythonEnv); + mockPythonEnvApi.resolveEnvironment.resolves(mockPythonEnv); + + const result = await pythonApi.getSettingsPythonPath(); + + expect(result).to.deep.equal(expectedPath); + }); + + test('Should return execution details for specific resource', async () => { + const resource = Uri.file(WORKSPACE_FILE); + const expectedPath = [PYTHON_PATH]; + // OLD API: Using getEnvironment() + resolveEnvironment() instead of settings.getExecutionDetails + const mockPythonEnv = buildPythonEnvironment(PYTHON_PATH, '3.9.0'); + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.resolves(mockPythonEnv); + mockPythonEnvApi.resolveEnvironment.resolves(mockPythonEnv); + + const result = await pythonApi.getSettingsPythonPath(resource); + + expect(result).to.deep.equal(expectedPath); + // OLD API: Using getEnvironment() instead of settings.getExecutionDetails + sinon.assert.calledWith(mockPythonEnvApi.getEnvironment, resource); + }); + + test('Should return undefined when execCommand is not available', async () => { + // OLD API: Using getEnvironment() instead of settings.getExecutionDetails + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.resolves(undefined); + + const result = await pythonApi.getSettingsPythonPath(); + + expect(result).to.be.undefined; + }); + }); + + suite('getEnvironmentVariables', () => { + test('Should return environment variables from Python extension API', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: PYTHON_PATH_DIR, PYTHONPATH: PYTHON_LIB_PYTHON3_DIR }; + // OLD API: Using getEnvironmentVariables() instead of environments.getEnvironmentVariables + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironmentVariables.resolves(expectedVars); + + const result = await pythonApi.getEnvironmentVariables(); + + expect(result).to.deep.equal(expectedVars); + // OLD API: Using getEnvironmentVariables() instead of environments.getEnvironmentVariables + sinon.assert.calledWith(mockPythonEnvApi.getEnvironmentVariables, sinon.match.any); + }); + + test('Should get environment variables for specific resource', async () => { + const resource = Uri.file(WORKSPACE_FILE); + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: PYTHON_PATH_DIR }; + // OLD API: Using getEnvironmentVariables() instead of environments.getEnvironmentVariables + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironmentVariables.resolves(expectedVars); + + const result = await pythonApi.getEnvironmentVariables(resource); + + expect(result).to.deep.equal(expectedVars); + // OLD API: Using getEnvironmentVariables() instead of environments.getEnvironmentVariables + sinon.assert.calledWith(mockPythonEnvApi.getEnvironmentVariables, resource); + }); + + test('Should handle undefined resource and return workspace environment variables', async () => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const expectedVars = { PATH: PYTHON_PATH_DIR, PYTHONPATH: WORKSPACE_PYTHON_DIR }; + // OLD API: Using getEnvironmentVariables() instead of environments.getEnvironmentVariables + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironmentVariables.resolves(expectedVars); + + const result = await pythonApi.getEnvironmentVariables(undefined); + + expect(result).to.deep.equal(expectedVars); + // OLD API: Using getEnvironmentVariables() instead of environments.getEnvironmentVariables + sinon.assert.calledWith(mockPythonEnvApi.getEnvironmentVariables, undefined); + }); + }); + + suite('resolveEnvironment', () => { + test('Should resolve environment from path string', async () => { + const envPath = PYTHON_PATH; + // Use buildPythonEnvironment for realistic mock + const expectedEnv = buildPythonEnvironment(envPath, '3.9.0'); + + // OLD API: Using resolveEnvironment() instead of environments.resolveEnvironment + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.resolveEnvironment.resolves(expectedEnv); + + const result = await pythonApi.resolveEnvironment(envPath); + + expect(result).to.deep.equal(expectedEnv); + // OLD API: Using resolveEnvironment() instead of environments.resolveEnvironment + // sinon.assert.calledWith(mockPythonEnvApi.resolveEnvironment, envPath); + }); + + test('Should resolve environment from Environment object', async () => { + // Use buildPythonEnvironment for realistic mock + const expectedEnv = buildPythonEnvironment(PYTHON_PATH, '3.9.0'); + + // OLD API: Using resolveEnvironment() instead of environments.resolveEnvironment + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.resolveEnvironment.resolves(expectedEnv); + + const result = await pythonApi.resolveEnvironment(expectedEnv.environmentPath.fsPath); + + expect(result).to.deep.equal(expectedEnv); + }); + + test('Should return undefined for invalid environment', async () => { + const envPath = INVALID_PATH; + // OLD API: Using resolveEnvironment() instead of environments.resolveEnvironment + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.resolveEnvironment.resolves(undefined); + + const result = await pythonApi.resolveEnvironment(envPath); + + expect(result).to.be.undefined; + }); + }); + + suite('getActiveEnvironmentPath', () => { + test('Should return active environment path', async () => { + // Match production shape: getEnvironment() returns a PythonEnvironment-like object + const envObj = buildPythonEnvironment(PYTHON_PATH, '3.9.0'); + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.returns(envObj); + + const result = await pythonApi.getActiveEnvironmentPath(); + + expect((result as any).environmentPath.fsPath).to.equal(PYTHON_PATH); + expect((result as any).execInfo.run.executable).to.equal(PYTHON_PATH); + }); + + test('Should return active environment path for specific resource', async () => { + const resource = Uri.file(WORKSPACE_FILE); + const envObj = buildPythonEnvironment(PYTHON_PATH, '3.9.0'); + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.returns(envObj); + + const result = await pythonApi.getActiveEnvironmentPath(resource); + + expect((result as any).environmentPath.fsPath).to.equal(PYTHON_PATH); + sinon.assert.calledWith(mockPythonEnvApi.getEnvironment, resource); + }); + }); + + suite('getInterpreterDetails', () => { + test('Should return interpreter details without resource', async () => { + const pythonPath = PYTHON_PATH; + const mockEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + // OLD API: Using getEnvironment() and resolveEnvironment() instead of environments.* + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(pythonPath) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + const result = await pythonApi.getInterpreterDetails(); + + // Use Uri.file().fsPath to get platform-normalized path for comparison + expect(result.path).to.deep.equal([Uri.file(pythonPath).fsPath]); + expect(result.resource).to.be.undefined; + }); + + test('Should return interpreter details with resource', async () => { + const resource = Uri.file(WORKSPACE_FILE); + const pythonPath = PYTHON_PATH; + const mockEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + // OLD API: Using getEnvironment() and resolveEnvironment() instead of environments.* + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(pythonPath) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + const result = await pythonApi.getInterpreterDetails(resource); + + // Use Uri.file().fsPath to get platform-normalized path for comparison + expect(result.path).to.deep.equal([Uri.file(pythonPath).fsPath]); + expect(result.resource).to.deep.equal(resource); + }); + + test('Should not quote path with spaces', async () => { + // this should be updated when we fix the quoting logic in getInterpreterDetails + const pythonPath = PYTHON_PATH_WITH_SPACES; + const mockEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + // OLD API: Using getEnvironment() and resolveEnvironment() instead of environments.* + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(pythonPath) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.deep.equal([`${pythonPath}`]); + }); + + test('Should not double-quote already quoted path', async () => { + const quotedPython = Uri.file(QUOTED_PYTHON_PATH); + const quotedPythonPath = quotedPython.fsPath; + const mockEnv = buildPythonEnvironment(quotedPythonPath, '3.9.0'); + + // OLD API: Using getEnvironment() and resolveEnvironment() instead of environments.* + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.returns({ environmentPath: quotedPython }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.deep.equal([quotedPythonPath]); + }); + + test('Should return undefined path when environment is not resolved', async () => { + // OLD API: Using getEnvironment() and resolveEnvironment() instead of environments.* + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(PYTHON_PATH) }); + mockPythonEnvApi.resolveEnvironment.resolves(undefined); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.be.undefined; + expect(result.resource).to.be.undefined; + }); + + test('Should return undefined path when executable uri is not available', async () => { + const mockEnv = { + id: 'test-env', + execInfo: { + run: { executable: undefined, args: [] }, + }, + } as any; + + // OLD API: Using getEnvironment() and resolveEnvironment() instead of environments.* + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(PYTHON_PATH) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + const result = await pythonApi.getInterpreterDetails(); + + expect(result.path).to.be.undefined; + }); + }); + + suite('onDidChangePythonInterpreter event', () => { + test('Should fire event when active environment path changes', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + const pythonPath = PYTHON_PATH_39; + const mockEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + // OLD API: Using onDidChangeEnvironments instead of onDidChangeActiveEnvironmentPath + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.onDidChangeEnvironments = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + // Set up mocks for getInterpreterDetails() call in event handler + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(pythonPath) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Trigger the environment change event + await eventCallback(); + + // Should be called at least twice: once during init, once from the event + expect(mockEventHandler.callCount).to.be.greaterThan(1); + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal([pythonPath]); + expect(lastCall.resource).to.be.undefined; + }); + + test('Should handle WorkspaceFolder resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + const pythonPath = PYTHON_PATH_39; + const mockEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + // OLD API: Using onDidChangeEnvironments instead of onDidChangeActiveEnvironmentPath + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.onDidChangeEnvironments = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + // Set up mocks for getInterpreterDetails() call in event handler + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(pythonPath) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Trigger the environment change event + await eventCallback(); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal([pythonPath]); + expect(lastCall.resource).to.be.undefined; + }); + + test('Should handle null resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + const pythonPath = PYTHON_PATH_39; + const mockEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + // OLD API: Using onDidChangeEnvironments instead of onDidChangeActiveEnvironmentPath + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.onDidChangeEnvironments = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + // Set up mocks for getInterpreterDetails() call in event handler + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(pythonPath) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Trigger the environment change event + await eventCallback(); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal([pythonPath]); + expect(lastCall.resource).to.be.undefined; + }); + + test('Should handle undefined resource in event', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + const pythonPath = PYTHON_PATH_39; + const mockEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + // OLD API: Using onDidChangeEnvironments instead of onDidChangeActiveEnvironmentPath + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.onDidChangeEnvironments = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + // Set up mocks for getInterpreterDetails() call in event handler + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(pythonPath) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Trigger the environment change event + await eventCallback(); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal([pythonPath]); + expect(lastCall.resource).to.be.undefined; + }); + + test('Should handle event with missing id', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + const pythonPath = PYTHON_PATH_39; + const mockEnv = buildPythonEnvironment(pythonPath, '3.9.0'); + + // OLD API: Using onDidChangeEnvironments instead of onDidChangeActiveEnvironmentPath + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.onDidChangeEnvironments = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + // Set up mocks for getInterpreterDetails() call in event handler + mockPythonEnvApi.getEnvironment.returns({ environmentPath: Uri.file(pythonPath) }); + mockPythonEnvApi.resolveEnvironment.resolves(mockEnv); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Trigger the environment change event + await eventCallback(); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.deep.equal([pythonPath]); + expect(lastCall.resource).to.be.undefined; + }); + + test('Should handle event with null path', async () => { + const disposables: Disposable[] = []; + let eventCallback: any; + const mockEventHandler = sinon.stub(); + + // OLD API: Using onDidChangeEnvironments instead of onDidChangeActiveEnvironmentPath + (mockEnvsExtension as any).exports = mockPythonEnvApi; + mockPythonEnvApi.onDidChangeEnvironments = (callback: any) => { + eventCallback = callback; + return { dispose: sinon.stub() }; + }; + // Test case where getEnvironment returns no environment (null path case) + mockPythonEnvApi.getEnvironment.returns(undefined); + mockPythonEnvApi.resolveEnvironment.resolves(undefined); + + pythonApi.onDidChangePythonInterpreter(mockEventHandler); + + await pythonApi.initializePython(disposables); + + // Trigger the environment change event + await eventCallback(); + + const lastCall = mockEventHandler.lastCall.args[0]; + expect(lastCall.path).to.be.undefined; + expect(lastCall.resource).to.be.undefined; + }); + }); +}); diff --git a/src/test/unittest/configuration/providers/pyramidLaunch.unit.test.ts b/src/test/unittest/configuration/providers/pyramidLaunch.unit.test.ts index e04acada..8aaad1a9 100644 --- a/src/test/unittest/configuration/providers/pyramidLaunch.unit.test.ts +++ b/src/test/unittest/configuration/providers/pyramidLaunch.unit.test.ts @@ -12,10 +12,10 @@ import { Uri } from 'vscode'; import { DebugConfigStrings } from '../../../../extension/common/utils/localize'; import { MultiStepInput } from '../../../../extension/common/multiStepInput'; import { DebuggerTypeName } from '../../../../extension/constants'; -import { resolveVariables } from '../../../../extension/debugger/configuration/utils/common'; import * as pyramidLaunch from '../../../../extension/debugger/configuration/providers/pyramidLaunch'; import { DebugConfigurationState } from '../../../../extension/debugger/types'; import * as vscodeapi from '../../../../extension/common/vscodeapi'; +import { resolveWorkspaceVariables } from '../../../../extension/debugger/configuration/utils/common'; suite('Debugging - Configuration Provider Pyramid', () => { let input: MultiStepInput; @@ -52,7 +52,7 @@ suite('Debugging - Configuration Provider Pyramid', () => { test('Resolve variables (with resource)', async () => { const folder = { uri: Uri.parse(path.join('one', 'two')), name: '1', index: 0 }; workspaceStub.returns(folder); - const resolvedPath = resolveVariables('${workspaceFolder}/one.py', undefined, folder); + const resolvedPath = resolveWorkspaceVariables('${workspaceFolder}/one.py', undefined, folder); expect(resolvedPath).to.be.equal(`${folder.uri.fsPath}/one.py`); }); diff --git a/src/test/unittest/configuration/resolvers/base.unit.test.ts b/src/test/unittest/configuration/resolvers/base.unit.test.ts index ae63c4b9..14765f6d 100644 --- a/src/test/unittest/configuration/resolvers/base.unit.test.ts +++ b/src/test/unittest/configuration/resolvers/base.unit.test.ts @@ -15,6 +15,7 @@ import * as helper from '../../../../extension/debugger/configuration/resolvers/ import * as vscodeapi from '../../../../extension/common/vscodeapi'; import { AttachRequestArguments, DebugOptions, LaunchRequestArguments } from '../../../../extension/types'; import { PythonEnvironment } from '../../../../extension/debugger/adapter/types'; +import { PythonPathSource } from '../../../../extension/debugger/types'; import * as pythonApi from '../../../../extension/common/python'; suite('Debugging - Config Resolver', () => { @@ -61,6 +62,10 @@ suite('Debugging - Config Resolver', () => { public isDebuggingFlask(debugConfiguration: Partial) { return BaseConfigurationResolver.isDebuggingFlask(debugConfiguration); } + + public getPythonPathSource() { + return this.pythonPathSource; + } } let resolver: BaseResolver; let getWorkspaceFoldersStub: sinon.SinonStub; @@ -311,3 +316,397 @@ suite('Debugging - Config Resolver', () => { expect(isFlask).to.equal(false, 'flask'); }); }); + +// Tests for prioritization of python path configuration +suite('resolveAndUpdatePythonPath prioritization tests', () => { + class BaseResolver2 extends BaseConfigurationResolver { + public resolveDebugConfiguration( + _folder: WorkspaceFolder | undefined, + _debugConfiguration: DebugConfiguration, + _token?: CancellationToken, + ): Promise { + throw new Error('Not Implemented'); + } + + public resolveDebugConfigurationWithSubstitutedVariables( + _folder: WorkspaceFolder | undefined, + _debugConfiguration: DebugConfiguration, + _token?: CancellationToken, + ): Promise { + throw new Error('Not Implemented'); + } + + public resolveAndUpdatePythonPath( + workspaceFolderUri: Uri | undefined, + debugConfiguration: LaunchRequestArguments, + ) { + return super.resolveAndUpdatePythonPath(workspaceFolderUri, debugConfiguration); + } + + public getPythonPathSource() { + return this.pythonPathSource; + } + } + + let resolver: BaseResolver2; + let getInterpreterDetailsStub: sinon.SinonStub; + + setup(() => { + resolver = new BaseResolver2(); + getInterpreterDetailsStub = sinon.stub(pythonApi, 'getInterpreterDetails'); + }); + + teardown(() => { + sinon.restore(); + }); + + test('When pythonPath is a concrete path and python is undefined, python should be set to pythonPath value', async () => { + const expectedPath = path.join('path', 'to', 'custom', 'python'); + const config = { + pythonPath: expectedPath, + python: undefined, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', expectedPath); + }); + + test('When pythonPath is a concrete path and python is a different concrete path, python should take precedence', async () => { + const pythonPathValue = path.join('path', 'to', 'pythonPath', 'python'); + const pythonValue = path.join('path', 'to', 'python', 'python'); + const config = { + pythonPath: pythonPathValue, + python: pythonValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonValue); + }); + + test('When pythonPath is ${command:python.interpreterPath} and python is a concrete path, python should take precedence', async () => { + const pythonValue = path.join('path', 'to', 'python', 'python'); + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: '${command:python.interpreterPath}', + python: pythonValue, + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonValue); + }); + + test('When pythonPath is a concrete path and python is ${command:python.interpreterPath}, python should resolve from interpreter', async () => { + const pythonPathValue = path.join('path', 'to', 'pythonPath', 'python'); + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: pythonPathValue, + python: '${command:python.interpreterPath}', + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', interpreterPath); + }); + + test('When both pythonPath and python are ${command:python.interpreterPath}, both should resolve to interpreter path', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: '${command:python.interpreterPath}', + python: '${command:python.interpreterPath}', + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', interpreterPath); + }); + + test('When pythonPath is not set and python is not set, both should resolve from interpreter', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = {}; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', interpreterPath); + }); + + test('debugAdapterPython should use pythonPath when neither debugAdapterPython nor python are set', async () => { + const pythonPathValue = path.join('path', 'to', 'custom', 'python'); + const config = { + pythonPath: pythonPathValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonPathValue); + expect(config).to.have.property('debugAdapterPython', pythonPathValue); + }); + + test('debugAdapterPython should use pythonPath when pythonPath is set but python has different value', async () => { + const pythonPathValue = path.join('path', 'to', 'pythonPath', 'python'); + const pythonValue = path.join('path', 'to', 'python', 'python'); + const config = { + pythonPath: pythonPathValue, + python: pythonValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonValue); + expect(config).to.have.property('debugAdapterPython', pythonPathValue); + }); + + test('debugAdapterPython should prefer explicitly set debugAdapterPython over pythonPath', async () => { + const pythonPathValue = path.join('path', 'to', 'pythonPath', 'python'); + const debugAdapterValue = path.join('path', 'to', 'debugAdapter', 'python'); + const config = { + pythonPath: pythonPathValue, + debugAdapterPython: debugAdapterValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonPathValue); + expect(config).to.have.property('debugAdapterPython', debugAdapterValue); + }); + + test('debugLauncherPython should use pythonPath when neither debugLauncherPython nor python are set', async () => { + const pythonPathValue = path.join('path', 'to', 'custom', 'python'); + const config = { + pythonPath: pythonPathValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonPathValue); + expect(config).to.have.property('debugLauncherPython', pythonPathValue); + }); + + test('debugLauncherPython should use pythonPath when pythonPath is set but python has different value', async () => { + const pythonPathValue = path.join('path', 'to', 'pythonPath', 'python'); + const pythonValue = path.join('path', 'to', 'python', 'python'); + const config = { + pythonPath: pythonPathValue, + python: pythonValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonValue); + expect(config).to.have.property('debugLauncherPython', pythonPathValue); + }); + + test('debugLauncherPython should prefer explicitly set debugLauncherPython over pythonPath', async () => { + const pythonPathValue = path.join('path', 'to', 'pythonPath', 'python'); + const debugLauncherValue = path.join('path', 'to', 'debugLauncher', 'python'); + const config = { + pythonPath: pythonPathValue, + debugLauncherPython: debugLauncherValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonPathValue); + expect(config).to.have.property('debugLauncherPython', debugLauncherValue); + }); + + test('All three debug python fields can have different values when explicitly set', async () => { + const pythonValue = path.join('path', 'to', 'python', 'python'); + const debugAdapterValue = path.join('path', 'to', 'debugAdapter', 'python'); + const debugLauncherValue = path.join('path', 'to', 'debugLauncher', 'python'); + const config = { + python: pythonValue, + debugAdapterPython: debugAdapterValue, + debugLauncherPython: debugLauncherValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonValue); + expect(config).to.have.property('debugAdapterPython', debugAdapterValue); + expect(config).to.have.property('debugLauncherPython', debugLauncherValue); + }); + + test('When debugAdapterPython is ${command:python.interpreterPath}, it should fallback to resolved pythonPath', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: '${command:python.interpreterPath}', + debugAdapterPython: '${command:python.interpreterPath}', + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', interpreterPath); + expect(config).to.have.property('debugAdapterPython', interpreterPath); + }); + + test('When debugLauncherPython is ${command:python.interpreterPath}, it should fallback to resolved pythonPath', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: '${command:python.interpreterPath}', + debugLauncherPython: '${command:python.interpreterPath}', + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', interpreterPath); + expect(config).to.have.property('debugLauncherPython', interpreterPath); + }); + + test('Complex scenario: pythonPath set, python differs, debugAdapterPython and debugLauncherPython both set differently', async () => { + const pythonPathValue = path.join('path', 'to', 'pythonPath', 'python'); + const pythonValue = path.join('path', 'to', 'python', 'python'); + const debugAdapterValue = path.join('path', 'to', 'debugAdapter', 'python'); + const debugLauncherValue = path.join('path', 'to', 'debugLauncher', 'python'); + const config = { + pythonPath: pythonPathValue, + python: pythonValue, + debugAdapterPython: debugAdapterValue, + debugLauncherPython: debugLauncherValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonValue); + expect(config).to.have.property('debugAdapterPython', debugAdapterValue); + expect(config).to.have.property('debugLauncherPython', debugLauncherValue); + }); + + test('When pythonPath is undefined and python is concrete path, debugAdapter and debugLauncher should use resolved pythonPath from interpreter', async () => { + const pythonValue = path.join('path', 'to', 'python', 'python'); + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + python: pythonValue, + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', pythonValue); + expect(config).to.have.property('debugAdapterPython', interpreterPath); + expect(config).to.have.property('debugLauncherPython', interpreterPath); + }); + + test('When pythonPath is empty string, it should be treated as not set and resolve from interpreter', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: '', + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(config).to.not.have.property('pythonPath'); + expect(config).to.have.property('python', interpreterPath); + }); + + // Tests for pythonPathSource field + test('pythonPathSource should be settingsJson when python is ${command:python.interpreterPath}', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + python: '${command:python.interpreterPath}', + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(resolver.getPythonPathSource()).to.equal(PythonPathSource.settingsJson); + }); + + test('pythonPathSource should be settingsJson when python is undefined', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: interpreterPath, + python: undefined, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(resolver.getPythonPathSource()).to.equal(PythonPathSource.settingsJson); + }); + + test('pythonPathSource should be launchJson when python is explicitly set to a concrete path', async () => { + const pythonValue = path.join('path', 'to', 'python', 'python'); + const config = { + python: pythonValue, + }; + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(resolver.getPythonPathSource()).to.equal(PythonPathSource.launchJson); + }); + + test('pythonPathSource should be launchJson when python is a concrete path even if pythonPath is ${command:python.interpreterPath}', async () => { + const pythonValue = path.join('path', 'to', 'python', 'python'); + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: '${command:python.interpreterPath}', + python: pythonValue, + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(resolver.getPythonPathSource()).to.equal(PythonPathSource.launchJson); + }); + + test('pythonPathSource should be settingsJson when both pythonPath and python are ${command:python.interpreterPath}', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = { + pythonPath: '${command:python.interpreterPath}', + python: '${command:python.interpreterPath}', + }; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(resolver.getPythonPathSource()).to.equal(PythonPathSource.settingsJson); + }); + + test('pythonPathSource should be settingsJson when neither pythonPath nor python are set', async () => { + const interpreterPath = path.join('path', 'from', 'interpreter'); + const config = {}; + + getInterpreterDetailsStub.resolves({ path: [interpreterPath] } as unknown as PythonEnvironment); + + await resolver.resolveAndUpdatePythonPath(undefined, config as LaunchRequestArguments); + + expect(resolver.getPythonPathSource()).to.equal(PythonPathSource.settingsJson); + }); +}); diff --git a/src/test/unittest/configuration/resolvers/launch.unit.test.ts b/src/test/unittest/configuration/resolvers/launch.unit.test.ts index d15e2cdf..d8b46eda 100644 --- a/src/test/unittest/configuration/resolvers/launch.unit.test.ts +++ b/src/test/unittest/configuration/resolvers/launch.unit.test.ts @@ -52,6 +52,15 @@ getInfoPerOS().forEach(([osName, osType, path]) => { getDebugEnvironmentVariablesStub = sinon.stub(helper, 'getDebugEnvironmentVariables'); getConfigurationStub = sinon.stub(vscodeapi, 'getConfiguration'); getConfigurationStub.withArgs('debugpy', sinon.match.any).returns(createMoqConfiguration(true)); + // Mock python configuration for useEnvExtension check + const pythonConfig = TypeMoq.Mock.ofType(); + pythonConfig.setup((p) => p.get('useEnvironmentsExtension', false)).returns(() => false); + getConfigurationStub.withArgs('python').returns(pythonConfig.object); + // Mock terminal configuration with default values + const terminalConfig = TypeMoq.Mock.ofType(); + terminalConfig.setup((c) => c.get(TypeMoq.It.isAnyString())).returns(() => undefined); + terminalConfig.setup((c) => c.get(TypeMoq.It.isAnyString())).returns(() => undefined); + getConfigurationStub.withArgs('terminal').returns(terminalConfig.object); }); teardown(() => { @@ -123,16 +132,19 @@ getInfoPerOS().forEach(([osName, osType, path]) => { if (config === undefined || config === null) { return config; } - const interpreterPath = await pythonApi.getActiveEnvironmentPath( + const activePythonEnv = await pythonApi.getActiveEnvironmentPath( workspaceFolder ? workspaceFolder.uri : undefined, ); + let interpreterPath = ''; + if (activePythonEnv && 'environmentPath' in activePythonEnv) { + interpreterPath = activePythonEnv.environmentPath.fsPath; + } else if (activePythonEnv && 'path' in activePythonEnv) { + interpreterPath = activePythonEnv.path; + } for (const key of Object.keys(config)) { const value = config[key]; if (typeof value === 'string') { - config[key] = value.replace( - '${command:python.interpreterPath}', - interpreterPath ? interpreterPath.path : '', - ); + config[key] = value.replace('${command:python.interpreterPath}', interpreterPath); } } @@ -1042,5 +1054,228 @@ getInfoPerOS().forEach(([osName, osType, path]) => { await testSetting(requestType, { subProcess: true }, DebugOptions.SubProcess, true); }); }); + + suite('terminalQuoteCharacter tests', () => { + let platformStub: sinon.SinonStub; + + function setupTerminalProfile( + profile: string | undefined, + path: string = 'bash', + platform: NodeJS.Platform = 'linux', + ) { + const terminalConfig = TypeMoq.Mock.ofType(); + + // Mock process.platform + if (platformStub) { + platformStub.restore(); + } + platformStub = sinon.stub(process, 'platform').value(platform); + + if (platform === 'win32') { + terminalConfig + .setup((c) => c.get('integrated.defaultProfile.windows')) + .returns(() => profile); + const profiles: any = {}; + if (profile) { + profiles[profile] = { path }; + } + terminalConfig.setup((c) => c.get('integrated.profiles.windows')).returns(() => profiles); + } else if (platform === 'linux') { + terminalConfig + .setup((c) => c.get('integrated.defaultProfile.linux')) + .returns(() => profile); + const profiles: any = {}; + if (profile) { + profiles[profile] = { path }; + } + terminalConfig.setup((c) => c.get('integrated.profiles.linux')).returns(() => profiles); + } else if (platform === 'darwin') { + terminalConfig.setup((c) => c.get('integrated.defaultProfile.osx')).returns(() => profile); + const profiles: any = {}; + if (profile) { + profiles[profile] = { path }; + } + terminalConfig.setup((c) => c.get('integrated.profiles.osx')).returns(() => profiles); + } + + getConfigurationStub.withArgs('terminal').returns(terminalConfig.object); + } + + test('Default terminalQuoteCharacter is computed for bash shell', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile('Bash', '/bin/bash', 'linux'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', '"'); + }); + + test('Default terminalQuoteCharacter is computed for zsh shell', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile('Zsh', '/bin/zsh', 'darwin'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', '"'); + }); + + test('Default terminalQuoteCharacter is computed for fish shell', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile('Fish', '/usr/bin/fish', 'linux'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', '"'); + }); + + test('Default terminalQuoteCharacter is computed for PowerShell', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile( + 'PowerShell', + 'C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', + 'win32', + ); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', "'"); + }); + + test('Default terminalQuoteCharacter is computed for cmd.exe', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile('Command Prompt', 'C:\\Windows\\System32\\cmd.exe', 'win32'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', '"'); + }); + + test('Default terminalQuoteCharacter is double quote when terminal profile is not configured', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile(undefined, 'bash', 'linux'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', '"'); + }); + + test('User-provided terminalQuoteCharacter is preserved when valid (single character)', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile('Bash', '/bin/bash', 'linux'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + terminalQuoteCharacter: "'", + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', "'"); + }); + + test('Invalid terminalQuoteCharacter (empty string) triggers fallback to computed default', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile('PowerShell', 'powershell.exe', 'win32'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + terminalQuoteCharacter: '', + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', "'"); + }); + + test('Invalid terminalQuoteCharacter (multi-character) triggers fallback to computed default', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile('Bash', '/bin/bash', 'linux'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + terminalQuoteCharacter: '""', + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', '"'); + }); + + test('terminalQuoteCharacter handles pwsh (PowerShell Core)', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile('PowerShell Core', '/usr/local/bin/pwsh', 'darwin'); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', "'"); + }); + + test('terminalQuoteCharacter is case-insensitive for shell detection', async () => { + const pythonPath = `PythonPath_${new Date().toString()}`; + const workspaceFolder = createMoqWorkspaceFolder(__dirname); + const pythonFile = 'xyz.py'; + setupIoc(pythonPath, workspaceFolder); + setupActiveEditor(pythonFile, PYTHON_LANGUAGE); + setupTerminalProfile( + 'PowerShell', + 'C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\POWERSHELL.EXE', + 'win32', + ); + + const debugConfig = await resolveDebugConfiguration(workspaceFolder, { + ...launch, + }); + + expect(debugConfig).to.have.property('terminalQuoteCharacter', "'"); + }); + }); }); }); diff --git a/src/test/unittest/index.ts b/src/test/unittest/index.ts index d1934133..3b085a4a 100644 --- a/src/test/unittest/index.ts +++ b/src/test/unittest/index.ts @@ -8,6 +8,7 @@ export function run(): Promise { const mocha = new Mocha({ ui: 'tdd', color: true, + grep: process.env.TEST_GREP, // Support filtering tests via environment variable }); const testsRoot = path.resolve(__dirname); diff --git a/src/test/unittest/inlineValue/pythonInlineValueProvider.unit.test.ts b/src/test/unittest/inlineValue/pythonInlineValueProvider.unit.test.ts index 53ca560c..13815205 100644 --- a/src/test/unittest/inlineValue/pythonInlineValueProvider.unit.test.ts +++ b/src/test/unittest/inlineValue/pythonInlineValueProvider.unit.test.ts @@ -10,7 +10,7 @@ import * as sinon from 'sinon'; import { use, expect } from 'chai'; import { EXTENSION_ROOT_DIR_FOR_TESTS } from '../../constants'; import { PythonInlineValueProvider } from '../../../extension/debugger/inlineValue/pythonInlineValueProvider'; -import { workspace, Range, InlineValueContext, WorkspaceConfiguration } from 'vscode'; +import { workspace, Range, InlineValueContext, WorkspaceConfiguration, InlineValue } from 'vscode'; import * as vscodeapi from '../../../extension/common/vscodeapi'; use(chaiAsPromised); @@ -98,102 +98,39 @@ suite('Debugging - pythonInlineProvider', () => { const context = { frameId: 0, stoppedLocation: new Range(4, 1, 4, 1) } as InlineValueContext; const result = await inlineValueProvider.provideInlineValues(document, viewPort, context); - const expected = [ + const expected: InlineValue[] = [ { - range: { - c: { - c: 0, - e: 0, - }, - e: { - c: 0, - e: 4, - }, - }, + range: new Range(0, 0, 0, 4), variableName: 'var1', caseSensitiveLookup: false, }, { - range: { - c: { - c: 0, - e: 6, - }, - e: { - c: 0, - e: 10, - }, - }, + range: new Range(0, 6, 0, 10), variableName: 'var2', caseSensitiveLookup: false, }, { - range: { - c: { - c: 1, - e: 0, - }, - e: { - c: 1, - e: 4, - }, - }, + range: new Range(1, 0, 1, 4), variableName: 'var3', caseSensitiveLookup: false, }, { - range: { - c: { - c: 2, - e: 0, - }, - e: { - c: 2, - e: 4, - }, - }, + range: new Range(2, 0, 2, 4), variableName: 'var4', caseSensitiveLookup: false, }, { - range: { - c: { - c: 3, - e: 0, - }, - e: { - c: 3, - e: 4, - }, - }, + range: new Range(3, 0, 3, 4), variableName: 'var5', caseSensitiveLookup: false, }, { - range: { - c: { - c: 4, - e: 7, - }, - e: { - c: 4, - e: 11, - }, - }, + range: new Range(4, 7, 4, 11), variableName: 'var1', caseSensitiveLookup: false, }, { - range: { - c: { - c: 4, - e: 14, - }, - e: { - c: 4, - e: 18, - }, - }, + range: new Range(4, 14, 4, 18), variableName: 'var2', caseSensitiveLookup: false, }, @@ -244,55 +181,19 @@ suite('Debugging - pythonInlineProvider', () => { const result = await inlineValueProvider.provideInlineValues(document, viewPort, context); const expected = [ { - range: { - c: { - c: 3, - e: 8, - }, - e: { - c: 3, - e: 17, - }, - }, + range: new Range(3, 8, 3, 17), expression: 'self.name', }, { - range: { - c: { - c: 4, - e: 8, - }, - e: { - c: 4, - e: 16, - }, - }, + range: new Range(4, 8, 4, 16), expression: 'self.age', }, { - range: { - c: { - c: 7, - e: 18, - }, - e: { - c: 7, - e: 27, - }, - }, + range: new Range(7, 18, 7, 27), expression: 'self.name', }, { - range: { - c: { - c: 7, - e: 29, - }, - e: { - c: 7, - e: 37, - }, - }, + range: new Range(7, 29, 7, 37), expression: 'self.age', }, ]; @@ -352,16 +253,7 @@ suite('Debugging - pythonInlineProvider', () => { const result = await inlineValueProvider.provideInlineValues(document, viewPort, context); const expected = [ { - range: { - c: { - c: 11, - e: 0, - }, - e: { - c: 11, - e: 10, - }, - }, + range: new Range(11, 0, 11, 10), expression: 'person1.id', }, ]; @@ -411,128 +303,47 @@ suite('Debugging - pythonInlineProvider', () => { const result = await inlineValueProvider.provideInlineValues(document, viewPort, context); const expected = [ { - range: { - c: { - c: 0, - e: 0, - }, - e: { - c: 0, - e: 9, - }, - }, + range: new Range(0, 0, 0, 9), variableName: 'some_list', caseSensitiveLookup: false, }, { - range: { - c: { - c: 1, - e: 0, - }, - e: { - c: 1, - e: 1, - }, - }, + range: new Range(1, 0, 1, 1), variableName: 'x', caseSensitiveLookup: false, }, { - range: { - c: { - c: 2, - e: 4, - }, - e: { - c: 2, - e: 5, - }, - }, + range: new Range(2, 4, 2, 5), variableName: 'n', caseSensitiveLookup: false, }, { - range: { - c: { - c: 2, - e: 13, - }, - e: { - c: 2, - e: 22, - }, - }, + range: new Range(2, 13, 2, 22), variableName: 'some_list', caseSensitiveLookup: false, }, { - range: { - c: { - c: 2, - e: 27, - }, - e: { - c: 2, - e: 28, - }, - }, + range: new Range(2, 27, 2, 28), variableName: 'x', caseSensitiveLookup: false, }, { - range: { - c: { - c: 3, - e: 13, - }, - e: { - c: 3, - e: 14, - }, - }, + range: new Range(3, 13, 3, 14), variableName: 'n', caseSensitiveLookup: false, }, { - range: { - c: { - c: 3, - e: 16, - }, - e: { - c: 3, - e: 17, - }, - }, + range: new Range(3, 16, 3, 17), variableName: 'x', caseSensitiveLookup: false, }, { - range: { - c: { - c: 5, - e: 13, - }, - e: { - c: 5, - e: 14, - }, - }, + range: new Range(5, 13, 5, 14), variableName: 'n', caseSensitiveLookup: false, }, { - range: { - c: { - c: 5, - e: 16, - }, - e: { - c: 5, - e: 17, - }, - }, + range: new Range(5, 16, 5, 17), variableName: 'x', caseSensitiveLookup: false, }, diff --git a/src/test/unittest/noConfigDebugInit.unit.test.ts b/src/test/unittest/noConfigDebugInit.unit.test.ts index 47f3a9fb..3cf6e401 100644 --- a/src/test/unittest/noConfigDebugInit.unit.test.ts +++ b/src/test/unittest/noConfigDebugInit.unit.test.ts @@ -71,7 +71,7 @@ suite('setup for no-config debug scenario', function () { .setup((x) => x.append(TypeMoq.It.isAny(), TypeMoq.It.isAny())) .callback((key, value) => { if (key === 'PATH') { - assert(value === `:${noConfigScriptsDir}`); + assert(value.includes(noConfigScriptsDir)); } }) .returns(envVarCollectionAppendStub); @@ -88,6 +88,100 @@ suite('setup for no-config debug scenario', function () { sinon.assert.calledOnce(envVarCollectionAppendStub); }); + test('should not add extra separator when PATH already ends with separator', async () => { + const environmentVariableCollectionMock = TypeMoq.Mock.ofType(); + envVarCollectionReplaceStub = sinon.stub(); + envVarCollectionAppendStub = sinon.stub(); + + // Simulate a PATH that already ends with a separator to test the fix + const pathSeparator = process.platform === 'win32' ? ';' : ':'; + const originalPath = process.env.PATH; + process.env.PATH = `/some/path${pathSeparator}`; + + try { + environmentVariableCollectionMock + .setup((x) => x.replace(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(envVarCollectionReplaceStub); + + environmentVariableCollectionMock + .setup((x) => x.append(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .callback((key, value) => { + if (key === 'PATH') { + // Since PATH already ends with separator, we should NOT add another one + assert(value === noConfigScriptsDir); + assert(!value.startsWith(pathSeparator)); + } + }) + .returns(envVarCollectionAppendStub); + + context + .setup((c) => c.environmentVariableCollection) + .returns(() => environmentVariableCollectionMock.object); + + setupFileSystemWatchers(); + + // run init for no config debug + await registerNoConfigDebug(context.object.environmentVariableCollection, context.object.extensionPath); + + // assert that append was called for PATH + sinon.assert.calledOnce(envVarCollectionAppendStub); + } finally { + // Restore original PATH + if (originalPath !== undefined) { + process.env.PATH = originalPath; + } else { + delete process.env.PATH; + } + } + }); + + test('should add separator when PATH does not end with separator', async () => { + const environmentVariableCollectionMock = TypeMoq.Mock.ofType(); + envVarCollectionReplaceStub = sinon.stub(); + envVarCollectionAppendStub = sinon.stub(); + + // Simulate a PATH that does NOT end with a separator + const pathSeparator = process.platform === 'win32' ? ';' : ':'; + const originalPath = process.env.PATH; + process.env.PATH = '/some/path'; + + try { + environmentVariableCollectionMock + .setup((x) => x.replace(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(envVarCollectionReplaceStub); + + environmentVariableCollectionMock + .setup((x) => x.append(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .callback((key, value) => { + if (key === 'PATH') { + // Since PATH does NOT end with separator, we should add one + assert(value === `${pathSeparator}${noConfigScriptsDir}`); + assert(value.startsWith(pathSeparator)); + } + }) + .returns(envVarCollectionAppendStub); + + context + .setup((c) => c.environmentVariableCollection) + .returns(() => environmentVariableCollectionMock.object); + + setupFileSystemWatchers(); + + // run init for no config debug + await registerNoConfigDebug(context.object.environmentVariableCollection, context.object.extensionPath); + + // assert that append was called for PATH + sinon.assert.calledOnce(envVarCollectionAppendStub); + } finally { + // Restore original PATH + if (originalPath !== undefined) { + process.env.PATH = originalPath; + } else { + delete process.env.PATH; + } + } + }); + test('should create file system watcher for debuggerAdapterEndpointFolder', async () => { // Arrange const environmentVariableCollectionMock = TypeMoq.Mock.ofType(); @@ -99,7 +193,10 @@ suite('setup for no-config debug scenario', function () { // Assert sinon.assert.calledOnce(createFileSystemWatcherFunct); - const expectedPattern = new RelativePattern(path.join(os.tmpdir(), '.noConfigDebugAdapterEndpoints'), '**/*'); + const expectedPattern = new RelativePattern( + path.join(os.tmpdir(), '.noConfigDebugAdapterEndpoints'), + '**/*.txt', + ); sinon.assert.calledWith(createFileSystemWatcherFunct, expectedPattern); });