diff --git a/.azure-pipelines/ci-build.yml b/.azure-pipelines/ci-build.yml index 898c03946a..c9ebf81771 100644 --- a/.azure-pipelines/ci-build.yml +++ b/.azure-pipelines/ci-build.yml @@ -116,6 +116,44 @@ extends: artifactName: AppSettings targetPath: "$(Build.ArtifactStagingDirectory)/AppSettings" + # upload the scripts directory as scripts artifact + + - task: 1ES.PublishPipelineArtifact@1 + displayName: "Publish Artifact: scripts" + inputs: + artifactName: scripts + targetPath: $(Build.SourcesDirectory)/scripts + + # upload the csproj file as csproj artifact + + - task: CopyFiles@2 + displayName: Prepare staging folder for upload + inputs: + targetFolder: $(Build.ArtifactStagingDirectory)/csproj + sourceFolder: $(Build.SourcesDirectory)/src/kiota + Contents: "*.csproj" + + - task: 1ES.PublishPipelineArtifact@1 + displayName: "Publish Artifact: csproj" + inputs: + artifactName: csproj + targetPath: "$(Build.ArtifactStagingDirectory)/csproj" + + # upload the changelog file as changelog artifact + + - task: CopyFiles@2 + displayName: Prepare staging folder for upload + inputs: + targetFolder: $(Build.ArtifactStagingDirectory)/changelog + sourceFolder: $(Build.SourcesDirectory) + Contents: "CHANGELOG.md" + + - task: 1ES.PublishPipelineArtifact@1 + displayName: "Publish Artifact: changelog" + inputs: + artifactName: changelog + targetPath: "$(Build.ArtifactStagingDirectory)/changelog" + - job: build dependsOn: [update_appsettings] pool: @@ -128,17 +166,15 @@ extends: baselineFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnbaselines suppression: suppressionFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnsuppress + inputs: + - input: pipelineArtifact + artifactName: AppSettings + targetPath: $(Build.ArtifactStagingDirectory)/AppSettings steps: - checkout: self clean: true submodules: true - - task: DownloadPipelineArtifact@2 - inputs: - artifact: AppSettings - source: current - targetPath: $(Build.ArtifactStagingDirectory)/AppSettings - - pwsh: | Copy-Item $(Build.ArtifactStagingDirectory)/AppSettings/appsettings.json $(Build.SourcesDirectory)/src/kiota/appsettings.json -Force -Verbose displayName: Copy the appsettings.json @@ -206,12 +242,12 @@ extends: - task: EsrpCodeSigning@5 displayName: "ESRP CodeSigning" inputs: - ConnectedServiceName: 'Federated DevX ESRP Managed Identity Connection' - AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' - AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' - AuthAKVName: 'akv-prod-eastus' - AuthCertName: 'ReferenceLibraryPrivateCert' - AuthSignCertName: 'ReferencePackagePublisherCertificate' + ConnectedServiceName: "Federated DevX ESRP Managed Identity Connection" + AppRegistrationClientId: "65035b7f-7357-4f29-bf25-c5ee5c3949f8" + AppRegistrationTenantId: "cdc5aeea-15c5-4db6-b079-fcadd2505dc2" + AuthAKVName: "akv-prod-eastus" + AuthCertName: "ReferenceLibraryPrivateCert" + AuthSignCertName: "ReferencePackagePublisherCertificate" FolderPath: '$(Build.SourcesDirectory)\src' signConfigType: inlineSignParams UseMinimatch: true @@ -281,12 +317,12 @@ extends: - task: EsrpCodeSigning@5 displayName: "ESRP CodeSigning Nuget Packages" inputs: - ConnectedServiceName: 'Federated DevX ESRP Managed Identity Connection' - AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' - AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' - AuthAKVName: 'akv-prod-eastus' - AuthCertName: 'ReferenceLibraryPrivateCert' - AuthSignCertName: 'ReferencePackagePublisherCertificate' + ConnectedServiceName: "Federated DevX ESRP Managed Identity Connection" + AppRegistrationClientId: "65035b7f-7357-4f29-bf25-c5ee5c3949f8" + AppRegistrationTenantId: "cdc5aeea-15c5-4db6-b079-fcadd2505dc2" + AuthAKVName: "akv-prod-eastus" + AuthCertName: "ReferenceLibraryPrivateCert" + AuthSignCertName: "ReferencePackagePublisherCertificate" FolderPath: "$(Build.ArtifactStagingDirectory)" UseMinimatch: true Pattern: "*.nupkg" @@ -318,7 +354,7 @@ extends: inputs: targetFolder: $(Build.ArtifactStagingDirectory)/Nugets sourceFolder: $(Build.ArtifactStagingDirectory) - content: "*.nupkg" + Contents: "*.*nupkg" - task: 1ES.PublishPipelineArtifact@1 displayName: "Publish Artifact: Nugets" @@ -341,6 +377,10 @@ extends: baselineFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnbaselines suppression: suppressionFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnsuppress + inputs: + - input: pipelineArtifact + artifactName: AppSettings + targetPath: $(Build.ArtifactStagingDirectory)/AppSettings steps: - checkout: self @@ -355,12 +395,6 @@ extends: inputs: version: 8.x - - task: DownloadPipelineArtifact@2 - inputs: - artifact: AppSettings - source: current - targetPath: $(Build.ArtifactStagingDirectory)/AppSettings - - pwsh: | Copy-Item $(Build.ArtifactStagingDirectory)/AppSettings/appsettings.json $(Build.SourcesDirectory)/src/kiota/appsettings.json -Force -Verbose displayName: Copy the appsettings.json @@ -401,12 +435,12 @@ extends: - task: EsrpCodeSigning@5 condition: and(succeeded(), startsWith('${{ distribution.architecture }}', 'win')) inputs: - ConnectedServiceName: 'Federated DevX ESRP Managed Identity Connection' - AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' - AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' - AuthAKVName: 'akv-prod-eastus' - AuthCertName: 'ReferenceLibraryPrivateCert' - AuthSignCertName: 'ReferencePackagePublisherCertificate' + ConnectedServiceName: "Federated DevX ESRP Managed Identity Connection" + AppRegistrationClientId: "65035b7f-7357-4f29-bf25-c5ee5c3949f8" + AppRegistrationTenantId: "cdc5aeea-15c5-4db6-b079-fcadd2505dc2" + AuthAKVName: "akv-prod-eastus" + AuthCertName: "ReferenceLibraryPrivateCert" + AuthSignCertName: "ReferencePackagePublisherCertificate" FolderPath: $(Build.ArtifactStagingDirectory)/binaries/${{ distribution.architecture }} signConfigType: inlineSignParams UseMinimatch: true @@ -469,12 +503,12 @@ extends: timeoutInMinutes: 15 retryCountOnTaskFailure: 4 inputs: - ConnectedServiceName: 'Federated DevX ESRP Managed Identity Connection' - AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' - AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' - AuthAKVName: 'akv-prod-eastus' - AuthCertName: 'ReferenceLibraryPrivateCert' - AuthSignCertName: 'ReferencePackagePublisherCertificate' + ConnectedServiceName: "Federated DevX ESRP Managed Identity Connection" + AppRegistrationClientId: "65035b7f-7357-4f29-bf25-c5ee5c3949f8" + AppRegistrationTenantId: "cdc5aeea-15c5-4db6-b079-fcadd2505dc2" + AuthAKVName: "akv-prod-eastus" + AuthCertName: "ReferenceLibraryPrivateCert" + AuthSignCertName: "ReferencePackagePublisherCertificate" FolderPath: $(Build.ArtifactStagingDirectory)/binaries signConfigType: inlineSignParams UseMinimatch: true @@ -501,12 +535,12 @@ extends: timeoutInMinutes: 15 retryCountOnTaskFailure: 4 inputs: - ConnectedServiceName: 'Federated DevX ESRP Managed Identity Connection' - AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' - AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' - AuthAKVName: 'akv-prod-eastus' - AuthCertName: 'ReferenceLibraryPrivateCert' - AuthSignCertName: 'ReferencePackagePublisherCertificate' + ConnectedServiceName: "Federated DevX ESRP Managed Identity Connection" + AppRegistrationClientId: "65035b7f-7357-4f29-bf25-c5ee5c3949f8" + AppRegistrationTenantId: "cdc5aeea-15c5-4db6-b079-fcadd2505dc2" + AuthAKVName: "akv-prod-eastus" + AuthCertName: "ReferenceLibraryPrivateCert" + AuthSignCertName: "ReferencePackagePublisherCertificate" FolderPath: $(Build.ArtifactStagingDirectory)/binaries signConfigType: inlineSignParams UseMinimatch: true @@ -554,6 +588,11 @@ extends: baselineFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnbaselines suppression: suppressionFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnsuppress + inputs: + - ${{ each distribution in parameters.distributions }}: + - input: pipelineArtifact + artifactName: Binaries_${{ distribution.jobPrefix }} + targetPath: $(Build.ArtifactStagingDirectory)/Binaries steps: - checkout: self clean: true @@ -561,13 +600,6 @@ extends: - task: NodeTool@0 inputs: versionSpec: "18.x" - - ${{ each distribution in parameters.distributions }}: - - task: DownloadPipelineArtifact@2 - displayName: Download ${{ distribution.jobPrefix }} binaries from artifacts - inputs: - artifact: Binaries_${{ distribution.jobPrefix }} - source: current - targetPath: $(Build.ArtifactStagingDirectory)/Binaries - pwsh: $(Build.SourcesDirectory)/scripts/get-prerelease-version.ps1 -currentBranch $(Build.SourceBranch) -previewBranch ${{ parameters.previewBranch }} displayName: "Set version suffix" - pwsh: $(Build.SourcesDirectory)/scripts/get-version-from-csproj.ps1 @@ -599,19 +631,19 @@ extends: workingDirectory: $(Build.SourcesDirectory)/vscode/microsoft-kiota name: getExtensionFileName - script: vsce generate-manifest -i $(getExtensionFileName.extensionFileName).vsix -o $(getExtensionFileName.extensionFileName).manifest - displayName: 'Generate extension manifest' + displayName: "Generate extension manifest" workingDirectory: $(Build.SourcesDirectory)/vscode/microsoft-kiota - script: cp $(getExtensionFileName.extensionFileName).manifest $(getExtensionFileName.extensionFileName).signature.p7s - displayName: 'Prepare manifest for signing' + displayName: "Prepare manifest for signing" workingDirectory: $(Build.SourcesDirectory)/vscode/microsoft-kiota - task: EsrpCodeSigning@5 inputs: - ConnectedServiceName: 'Federated DevX ESRP Managed Identity Connection' - AppRegistrationClientId: '65035b7f-7357-4f29-bf25-c5ee5c3949f8' - AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' - AuthAKVName: 'akv-prod-eastus' - AuthCertName: 'ReferenceLibraryPrivateCert' - AuthSignCertName: 'ReferencePackagePublisherCertificate' + ConnectedServiceName: "Federated DevX ESRP Managed Identity Connection" + AppRegistrationClientId: "65035b7f-7357-4f29-bf25-c5ee5c3949f8" + AppRegistrationTenantId: "cdc5aeea-15c5-4db6-b079-fcadd2505dc2" + AuthAKVName: "akv-prod-eastus" + AuthCertName: "ReferenceLibraryPrivateCert" + AuthSignCertName: "ReferencePackagePublisherCertificate" FolderPath: $(Build.SourcesDirectory)/vscode/microsoft-kiota UseMinimatch: true Pattern: '**\*.signature.p7s' @@ -630,7 +662,7 @@ extends: MaxConcurrency: 25 MaxRetryAttempts: 5 PendingAnalysisWaitTimeoutMinutes: 5 - displayName: 'Sign extension' + displayName: "Sign extension" - task: CopyFiles@2 displayName: Prepare staging folder for upload inputs: @@ -656,36 +688,32 @@ extends: os: linux image: ubuntu-latest templateContext: - sdl: - baseline: - baselineFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnbaselines - suppression: - suppressionFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnsuppress + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + artifactName: VSCode + targetPath: $(Pipeline.Workspace)/VSCode + - input: pipelineArtifact + artifactName: scripts + targetPath: "$(Pipeline.Workspace)/scripts" dependsOn: - github_release steps: - - download: none - - checkout: self - clean: true - submodules: true - - task: DownloadPipelineArtifact@2 - inputs: - artifact: VSCode - source: current - task: NodeTool@0 inputs: versionSpec: "18.x" - pwsh: npm i -g @vscode/vsce - - pwsh: $(Build.SourcesDirectory)/scripts/get-prerelease-version.ps1 -currentBranch $(Build.SourceBranch) -previewBranch ${{ parameters.previewBranch }} + - pwsh: $(Pipeline.Workspace)/scripts/get-prerelease-version.ps1 -currentBranch $(Build.SourceBranch) -previewBranch ${{ parameters.previewBranch }} displayName: "Set version suffix" - task: AzureCLI@2 inputs: azureSubscription: "kiota-vscode-marketplace-publish" scriptType: "pscore" - scriptLocation: 'inlineScript' + scriptLocation: "inlineScript" inlineScript: | $aadToken = az account get-access-token --query accessToken --resource 499b84ac-1321-427f-aa17-267ca6975798 -o tsv - Get-ChildItem -Path $(Pipeline.Workspace) -Filter *.vsix -Recurse | ForEach-Object { + Get-ChildItem -Path $(Pipeline.Workspace)/VSCode -Filter *.vsix -Recurse | ForEach-Object { $packagePath = $_.FullName $manifestPath = $packagePath.Replace("vsix", "manifest") $signaturePath = $packagePath.Replace("vsix", "signature.p7s") @@ -707,43 +735,41 @@ extends: os: linux image: ubuntu-latest templateContext: - sdl: - baseline: - baselineFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnbaselines - suppression: - suppressionFile: $(Build.SourcesDirectory)/guardian/SDL/common/.gdnsuppress + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + artifactName: VSCode + targetPath: "$(Pipeline.Workspace)" + - input: pipelineArtifact + artifactName: Nugets + targetPath: "$(Pipeline.Workspace)" + - input: pipelineArtifact + artifactName: scripts + targetPath: "$(Pipeline.Workspace)/scripts" + - input: pipelineArtifact + artifactName: csproj + targetPath: "$(Pipeline.Workspace)/csproj" + - input: pipelineArtifact + artifactName: changelog + targetPath: "$(Pipeline.Workspace)/changelog" + - ${{ each distribution in parameters.distributions }}: + - input: pipelineArtifact + artifactName: Binaries_${{ distribution.jobPrefix }} dependsOn: [] environment: kiota-github-releases strategy: runOnce: deploy: steps: - - download: none - - checkout: self - clean: true - submodules: true - - ${{ each distribution in parameters.distributions }}: - - task: DownloadPipelineArtifact@2 - displayName: Download ${{ distribution.jobPrefix }} binaries from artifacts - inputs: - artifact: Binaries_${{ distribution.jobPrefix }} - source: current - - task: DownloadPipelineArtifact@2 - inputs: - artifact: VSCode - source: current - - task: DownloadPipelineArtifact@2 - inputs: - artifact: Nugets - source: current - - pwsh: $(Build.SourcesDirectory)/scripts/get-prerelease-version.ps1 -currentBranch $(Build.SourceBranch) -previewBranch ${{ parameters.previewBranch }} + - pwsh: $(Pipeline.Workspace)/scripts/get-prerelease-version.ps1 -currentBranch $(Build.SourceBranch) -previewBranch ${{ parameters.previewBranch }} displayName: "Set version suffix" - - pwsh: $(Build.SourcesDirectory)/scripts/get-version-from-csproj.ps1 + - pwsh: $(Pipeline.Workspace)/scripts/get-version-from-csproj.ps1 -csprojPath "$(Pipeline.Workspace)/csproj/kiota.csproj" displayName: "Get Kiota's version-number from .csproj" - - pwsh: $(Build.SourcesDirectory)/scripts/get-release-notes.ps1 -version $(artifactVersion) -createNotes + - pwsh: $(Pipeline.Workspace)/scripts/get-release-notes.ps1 -version $(artifactVersion) -createNotes -changelogPath "$(Pipeline.Workspace)/changelog/CHANGELOG.md" condition: eq(variables['isPrerelease'], 'false') displayName: "Get release notes from CHANGELOG.md" - - pwsh: $(Build.SourcesDirectory)/scripts/get-release-notes.ps1 -version Unreleased -createNotes + - pwsh: $(Pipeline.Workspace)/scripts/get-release-notes.ps1 -version Unreleased -createNotes -changelogPath "$(Pipeline.Workspace)/changelog/CHANGELOG.md" condition: eq(variables['isPrerelease'], 'true') displayName: "Get release notes from CHANGELOG.md" - task: GitHubRelease@1 @@ -754,7 +780,7 @@ extends: tag: "v$(artifactVersion)" title: "v$(artifactVersion)" releaseNotesSource: filePath - releaseNotesFilePath: $(Build.SourcesDirectory)/release-notes.txt + releaseNotesFilePath: $(Pipeline.Workspace)/changelog/release-notes.txt assets: | $(Pipeline.Workspace)/*.zip $(Pipeline.Workspace)/*.vsix @@ -769,7 +795,7 @@ extends: tag: "v$(artifactVersion)$(versionSuffix)" title: "v$(artifactVersion)$(versionSuffix)" releaseNotesSource: filePath - releaseNotesFilePath: $(Build.SourcesDirectory)/release-notes.txt + releaseNotesFilePath: $(Pipeline.Workspace)/changelog/release-notes.txt assets: | $(Pipeline.Workspace)/*.zip $(Pipeline.Workspace)/*.vsix @@ -779,6 +805,13 @@ extends: isPreRelease: true - deployment: deploy_kiota + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + artifactName: Nugets + targetPath: "$(Pipeline.Workspace)" pool: name: Azure-Pipelines-1ESPT-ExDShared os: linux @@ -789,12 +822,6 @@ extends: runOnce: deploy: steps: - - download: none - - task: DownloadPipelineArtifact@2 - displayName: Download nupkg from artifacts - inputs: - artifact: Nugets - source: current - powershell: | Remove-Item "$(Pipeline.Workspace)/Microsoft.OpenApi.Kiota.Builder.*.nupkg" -Verbose displayName: remove other nupkgs to avoid duplication @@ -802,11 +829,18 @@ extends: displayName: "NuGet push" inputs: packagesToPush: "$(Pipeline.Workspace)/Microsoft.OpenApi.Kiota.*.nupkg" - packageParentPath: '$(Pipeline.Workspace)' + packageParentPath: "$(Pipeline.Workspace)" nuGetFeedType: external publishFeedCredentials: "OpenAPI Nuget Connection" - deployment: deploy_builder + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + artifactName: Nugets + targetPath: "$(Pipeline.Workspace)" pool: name: Azure-Pipelines-1ESPT-ExDShared os: linux @@ -817,12 +851,6 @@ extends: runOnce: deploy: steps: - - download: none - - task: DownloadPipelineArtifact@2 - displayName: Download nupkg from artifacts - inputs: - artifact: Nugets - source: current - powershell: | Remove-Item "$(Pipeline.Workspace)/Microsoft.OpenApi.Kiota.*.nupkg" -Verbose -Exclude "*.Builder.*" displayName: remove other nupkgs to avoid duplication @@ -830,6 +858,6 @@ extends: displayName: "NuGet push" inputs: packagesToPush: "$(Pipeline.Workspace)/Microsoft.OpenApi.Kiota.Builder.*.nupkg" - packageParentPath: '$(Pipeline.Workspace)' + packageParentPath: "$(Pipeline.Workspace)" nuGetFeedType: external publishFeedCredentials: "OpenAPI Nuget Connection" diff --git a/.github/ISSUE_TEMPLATE/01-kiota-bug.yml b/.github/ISSUE_TEMPLATE/01-kiota-bug.yml index c57677cabc..07a4b51dff 100644 --- a/.github/ISSUE_TEMPLATE/01-kiota-bug.yml +++ b/.github/ISSUE_TEMPLATE/01-kiota-bug.yml @@ -127,7 +127,7 @@ body: id: logs attributes: label: Debug output - description: Please copy and paste the output when using the `--debug`` flag. This will be automatically formatted into code, so no need for backticks. + description: Please copy and paste the output when using the `--ll debug`` flag. This will be automatically formatted into code, so no need for backticks. value: |
Click to expand log ``` diff --git a/.github/workflows/build-vscode-extension.yml b/.github/workflows/build-vscode-extension.yml index ee28133534..7b9742750e 100644 --- a/.github/workflows/build-vscode-extension.yml +++ b/.github/workflows/build-vscode-extension.yml @@ -10,7 +10,18 @@ permissions: contents: read jobs: + checksecret: + name: check if SONAR_TOKEN is set in github secrets + runs-on: ubuntu-latest + outputs: + is_SONAR_TOKEN_set: ${{ steps.checksecret_job.outputs.is_SONAR_TOKEN_set }} + steps: + - name: Check whether unity activation requests should be done + id: checksecret_job + run: | + echo "is_SONAR_TOKEN_set=${{ env.SONAR_TOKEN != '' }}" >> $GITHUB_OUTPUT build_extension: + needs: [checksecret] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -40,6 +51,7 @@ jobs: run: npm run test-with-coverage working-directory: vscode/microsoft-kiota - name: Run sonar cloud analysis + if: needs.checksecret.outputs.is_SONAR_TOKEN_set == 'true' uses: SonarSource/sonarcloud-github-action@master env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any diff --git a/.github/workflows/check-translations.yml b/.github/workflows/check-translations.yml new file mode 100644 index 0000000000..09b02848a1 --- /dev/null +++ b/.github/workflows/check-translations.yml @@ -0,0 +1,32 @@ +name: Check Translations + +on: + workflow_dispatch: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + check-translations: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.x + + - name: Run translation check + run: ./scripts/check-translations.ps1 + shell: pwsh + + - name: Upload untranslated strings + uses: actions/upload-artifact@v4 + with: + name: untranslated-strings + path: ./untranslated_strings.html diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d3ea8d16c9..b71c4288ab 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -25,7 +25,7 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build image - uses: docker/build-push-action@v6.9.0 + uses: docker/build-push-action@v6.10.0 with: push: false platforms: linux/amd64,linux/arm64/v8,linux/arm/v7 @@ -94,7 +94,7 @@ jobs: run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT - name: Push to GitHub Packages - Nightly if: contains(github.ref, env.PREVIEW_BRANCH) - uses: docker/build-push-action@v6.9.0 + uses: docker/build-push-action@v6.10.0 with: push: true platforms: linux/amd64,linux/arm64/v8,linux/arm/v7 @@ -104,7 +104,7 @@ jobs: # we can't get the sequence number from ADO so we default it back to github run number - name: Push to GitHub Packages - Release if: contains(github.ref, 'refs/tags/v') - uses: docker/build-push-action@v6.9.0 + uses: docker/build-push-action@v6.10.0 with: push: true platforms: linux/amd64,linux/arm64/v8,linux/arm/v7 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 8576c5848f..978bc0b184 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -87,7 +87,7 @@ jobs: if: matrix.language == 'go' uses: actions/setup-go@v5 with: - go-version: "^1.20" + go-version: "^1.23" - name: Setup Typescript if: matrix.language == 'typescript' uses: actions/setup-node@v4 diff --git a/.vscode/settings.json b/.vscode/settings.json index dd2e4eae3e..dbeb6ba174 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -51,5 +51,6 @@ "java.configuration.updateBuildConfiguration": "automatic", "dotnet-test-explorer.testProjectPath": "tests/**/*.Tests.csproj", "editor.formatOnSave": true, - "dotnet.defaultSolution": "kiota.sln" + "dotnet.defaultSolution": "kiota.sln", + "azure-pipelines.1ESPipelineTemplatesSchemaFile": true } diff --git a/CHANGELOG.md b/CHANGELOG.md index 55b6590f54..1a4befd77e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,8 +13,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Fixed Python error when a class inherits from a base class and implements an interface. [5637](https://github.com/microsoft/kiota/issues/5637) -- Fix anyOf/oneOf generation in TypeScript. [5353](https://github.com/microsoft/kiota/issues/5353) +- Fixed a bug in generation when a referenced schema in an allOf was a primitive [#5701](https://github.com/microsoft/kiota/issues/5701). +- Fixed a bug where inherited error models would be missing interface declarations. [#5888](https://github.com/microsoft/kiota/issues/5888) +- Fixed a bug where oneOf/anyOf schemas with single references to inheritance or intersections would be missing properties. [#5921](https://github.com/microsoft/kiota/issues/5921) + +## [1.21.0] - 2024-12-05 + +### Added + +- Added a notion of support experience for languages in preparation for new community implemented languages. + +### Changed + +- Fixed python generation in scenarios with opening/closing tags for code comments. [#5636](https://github.com/microsoft/kiota/issues/5636) +- Fixed Python error when a class inherits from a base class and implements an interface. [#5637](https://github.com/microsoft/kiota/issues/5637) +- Fixed a bug where one/any schemas with single schema entries would be missing properties. [#5808](https://github.com/microsoft/kiota/issues/5808) +- Fixed anyOf/oneOf generation in TypeScript. [5353](https://github.com/microsoft/kiota/issues/5353) +- Fixed invalid code in Php caused by "*/*/" in property description. [5635](https://github.com/microsoft/kiota/issues/5635) +- Fixed a bug where discriminator property name lookup could end up in an infinite loop. [#5771](https://github.com/microsoft/kiota/issues/5771) +- Fixed TypeScript generation error when generating usings from shaken serializers. [#5634](https://github.com/microsoft/kiota/issues/5634) +- Multiple fixed and improvements in OpenAPI description generation for plugins. [#5806](https://github.com/microsoft/kiota/issues/5806) ## [1.20.0] - 2024-11-07 @@ -152,7 +170,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added uri-form encoded serialization for PHP. [#2074](https://github.com/microsoft/kiota/issues/2074) - Added information message with base URL in the CLI experience. [#4635](https://github.com/microsoft/kiota/issues/4635) - Added optional parameter --disable-ssl-validation for generate, show, and download commands. [#4176](https://github.com/microsoft/kiota/issues/4176) -- For _Debug_ builds of kiota, the `--log-level` / `--ll` option is now observed if specified explicitly on the command line. It still defaults to `Debug` for _Debug_ builds and `Warning` for _Release_ builds. [#4739](https://github.com/microsoft/kiota/pull/4739) +- For *Debug* builds of kiota, the `--log-level` / `--ll` option is now observed if specified explicitly on the command line. It still defaults to `Debug` for *Debug* builds and `Warning` for *Release* builds. [#4739](https://github.com/microsoft/kiota/pull/4739) ### Changed @@ -754,7 +772,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed unused generated import for PHP Generation. - Fixed a bug where long namespaces would make Ruby packaging fail. - Fixed a bug where classes with namespace names are generated outside namespace in Python. [#2188](https://github.com/microsoft/kiota/issues/2188) -- Changed signature of escaped reserved names from {x}_escaped to {x}_ in line with Python style guides. +- Changed signature of escaped reserved names from {x}*escaped to {x}* in line with Python style guides. - Add null checks in generated Shell language code. - Fixed a bug where Go indexers would fail to pass the index parameter. - Fixed a bug where path segments with parameters could be missing words. [#2209](https://github.com/microsoft/kiota/issues/2209) @@ -1503,4 +1521,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Initial GitHub release - diff --git a/README.md b/README.md index 82761c3943..6bbf0d7137 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,14 @@ The following table provides an overview of the languages supported by Kiota and | Language | Generation | Abstractions | Serialization | Authentication | HTTP | Required tools & dependencies | | -------- | ---------- |--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -------------- | ---- | -------------- | +| CLI | 🛠️ | (see CSharp) + [🛠️](https://github.com/microsoft/kiota-cli-commons) | (see CSharp) | (see CSharp) | (see CSharp) | [link](https://learn.microsoft.com/openapi/kiota/quickstarts/cli) | | CSharp | ✔ | [✔](https://github.com/microsoft/kiota-dotnet/tree/main/src/abstractions) | [FORM](https://github.com/microsoft/kiota-dotnet/tree/main/src/serialization/form), [JSON](https://github.com/microsoft/kiota-dotnet/tree/main/src/serialization/json), [MULTIPART](https://github.com/microsoft/kiota-dotnet/tree/main/src/serialization/multipart), [TEXT](https://github.com/microsoft/kiota-dotnet/tree/main/src/serialization/text) | [Anonymous](https://github.com/microsoft/kiota-dotnet/blob/main/src/abstractions/authentication/AnonymousAuthenticationProvider.cs), [API Key](https://github.com/microsoft/kiota-dotnet/blob/main/src/abstractions/authentication/ApiKeyAuthenticationProvider.cs), [Azure](https://github.com/microsoft/kiota-dotnet/tree/main/src/authentication/azure) | [✔](https://github.com/microsoft/kiota-dotnet/tree/main/src/http/httpClient) | [link](https://learn.microsoft.com/openapi/kiota/quickstarts/dotnet) | +| Dart | [▶](https://github.com/kiota-community/kiota-dart/tree/features/dart) | [🛠️](https://github.com/kiota-community/dart_kiota/tree/main/packages/kiota_abstractions) | [🛠️ FORM](https://github.com/kiota-community/dart_kiota/tree/main/packages/kiota_serialization_form), [▶ JSON](https://github.com/kiota-community/dart_kiota/pull/35), [▶ MULTIPART](https://github.com/kiota-community/dart_kiota/pull/35), [🛠️ TEXT](https://github.com/kiota-community/dart_kiota/tree/main/packages/kiota_serialization_text) | [🛠️ Anonymous](https://github.com/kiota-community/dart_kiota/blob/main/packages/kiota_abstractions/lib/src/authentication/anonymous_authentication_provider.dart), [🛠️ API Key](https://github.com/kiota-community/dart_kiota/blob/main/packages/kiota_abstractions/lib/src/authentication/api_key_authentication_provider.dart) | [🛠️](https://github.com/kiota-community/dart_kiota/tree/main/packages/kiota_http) | | | Go | ✔ | [✔](https://github.com/microsoft/kiota-abstractions-go) | [FORM](https://github.com/microsoft/kiota-serialization-form-go), [JSON](https://github.com/microsoft/kiota-serialization-json-go), [MULTIPART](https://github.com/microsoft/kiota-serialization-multipart-go), [TEXT](https://github.com/microsoft/kiota-serialization-text-go) | [Anonymous](https://github.com/microsoft/kiota-abstractions-go/blob/main/authentication/anonymous_authentication_provider.go), [API Key](https://github.com/microsoft/kiota-abstractions-go/blob/main/authentication/api_key_authentication_provider.go), [Azure](https://github.com/microsoft/kiota-authentication-azure-go/) | [✔](https://github.com/microsoft/kiota-http-go/) | [link](https://learn.microsoft.com/openapi/kiota/quickstarts/go) | | Java | ✔ | [✔](https://github.com/microsoft/kiota-java/tree/main/components/abstractions) | [FORM](https://github.com/microsoft/kiota-java/tree/main/components/serialization/form), [JSON](https://github.com/microsoft/kiota-java/tree/main/components/serialization/json), [MULTIPART](https://github.com/microsoft/kiota-java/tree/main/components/serialization/multipart), [TEXT](https://github.com/microsoft/kiota-java/tree/main/components/serialization/text) | [Anonymous](https://github.com/microsoft/kiota-java/blob/main/components/abstractions/src/main/java/com/microsoft/kiota/authentication/AnonymousAuthenticationProvider.java), [API Key](https://github.com/microsoft/kiota-java/blob/main/components/abstractions/src/main/java/com/microsoft/kiota/authentication/ApiKeyAuthenticationProvider.java), [Azure](https://github.com/microsoft/kiota-java/tree/main/components/authentication/azure) | [✔](https://github.com/microsoft/kiota-java/tree/main/components/http/okHttp) | [link](https://learn.microsoft.com/openapi/kiota/quickstarts/java) | | PHP | ✔ | [✔](https://github.com/microsoft/kiota-abstractions-php) | [JSON](https://github.com/microsoft/kiota-serialization-json-php), [FORM](https://github.com/microsoft/kiota-serialization-form-php), [MULTIPART](https://github.com/microsoft/kiota-serialization-multipart-php), [TEXT](https://github.com/microsoft/kiota-serialization-text-php) | [Anonymous](https://github.com/microsoft/kiota-abstractions-php/blob/main/src/Authentication/AnonymousAuthenticationProvider.php), [✔️ PHP League](https://github.com/microsoft/kiota-authentication-phpleague-php) | [✔](https://github.com/microsoft/kiota-http-guzzle-php) | [link](https://learn.microsoft.com/openapi/kiota/quickstarts/php) | | Python | ✔ | [✔](https://github.com/microsoft/kiota-abstractions-python) | [FORM](https://github.com/microsoft/kiota-serialization-form-python), [JSON](https://github.com/microsoft/kiota-serialization-json-python), [MULTIPART](https://github.com/microsoft/kiota-serialization-multipart-python), [TEXT](https://github.com/microsoft/kiota-serialization-text-python) | [Anonymous](https://github.com/microsoft/kiota-abstractions-python/blob/main/kiota_abstractions/authentication/anonymous_authentication_provider.py), [Azure](https://github.com/microsoft/kiota-authentication-azure-python) | [✔](https://github.com/microsoft/kiota-http-python) | [link](https://learn.microsoft.com/openapi/kiota/quickstarts/python) | | Ruby | 🛠️ | [🛠️](https://github.com/microsoft/kiota-abstractions-ruby) | [❌ FORM](https://github.com/microsoft/kiota/issues/2077), [JSON](https://github.com/microsoft/kiota-serialization-json-ruby), [❌ MULTIPART](https://github.com/microsoft/kiota/issues/3032), [❌ TEXT](https://github.com/microsoft/kiota/issues/1049) | [Anonymous](https://github.com/microsoft/kiota-abstractions-ruby/blob/main/lib/microsoft_kiota_abstractions/authentication/anonymous_authentication_provider.rb), [OAuth2](https://github.com/microsoft/kiota-authentication-oauth-ruby) | [🛠️](https://github.com/microsoft/kiota-http-ruby)| | -| CLI | 🛠️ | (see CSharp) + [🛠️](https://github.com/microsoft/kiota-cli-commons) | (see CSharp) | (see CSharp) | (see CSharp) | [link](https://learn.microsoft.com/openapi/kiota/quickstarts/cli) | | Swift | [❌](https://github.com/microsoft/kiota/issues/1449) | [🛠️](./abstractions/swift) | [❌ FORM](https://github.com/microsoft/kiota/issues/2076), [❌ JSON](https://github.com/microsoft/kiota/issues/1451), [❌ FORM](https://github.com/microsoft/kiota/issues/3033), [❌ TEXT](https://github.com/microsoft/kiota/issues/1452) | [Anonymous](./abstractions/swift/Source/MicrosoftKiotaAbstractions/Authentication/AnonymousAuthenticationProvider.swift), [❌ Azure](https://github.com/microsoft/kiota/issues/1453) | [❌](https://github.com/microsoft/kiota/issues/1454)| | | TypeScript/JavaScript | 🛠️ | [🛠️](https://github.com/microsoft/kiota-typescript/tree/main/packages/abstractions) | [FORM](https://github.com/microsoft/kiota-typescript/tree/main/packages/serialization/form), [JSON](https://github.com/microsoft/kiota-typescript/tree/main/packages/serialization/json), [MULTIPART](https://github.com/microsoft/kiota-typescript/tree/main/packages/serialization/multipart), [TEXT](https://github.com/microsoft/kiota-typescript/tree/main/packages/serialization/text) | [Anonymous](https://github.com/microsoft/kiota-typescript/blob/main/packages/abstractions/src/authentication/anonymousAuthenticationProvider.ts), [API Key](https://github.com/microsoft/kiota-typescript/blob/main/packages/abstractions/src/authentication/apiKeyAuthenticationProvider.ts), [Azure](https://github.com/microsoft/kiota-typescript/tree/main/packages/authentication/azure), [SPFx](https://github.com/microsoft/kiota-typescript/tree/main/packages/authentication/spfx) | [🛠️](https://github.com/microsoft/kiota-typescript/tree/main/packages/http/fetch) | [link](https://learn.microsoft.com/openapi/kiota/quickstarts/typescript) | diff --git a/it/config.json b/it/config.json index 78f4d857ab..78cab6a5fe 100644 --- a/it/config.json +++ b/it/config.json @@ -29,21 +29,9 @@ "apisguru::github.com:api.github.com": { "MockServerITFolder": "gh", "Suppressions": [ - { - "Language": "typescript", - "Rationale": "https://github.com/microsoft/kiota/issues/5634" - }, - { - "Language": "php", - "Rationale": "https://github.com/microsoft/kiota/issues/5635" - }, { "Language": "ruby", "Rationale": "https://github.com/microsoft/kiota/issues/1816" - }, - { - "Language": "python", - "Rationale": "https://github.com/microsoft/kiota/issues/5636" } ], "ExcludePatterns": [ @@ -247,10 +235,6 @@ { "Language": "ruby", "Rationale": "https://github.com/microsoft/kiota/issues/2484" - }, - { - "Language": "python", - "Rationale": "https://github.com/microsoft/kiota/issues/5744" } ] }, @@ -267,4 +251,4 @@ "Suppressions": [], "IdempotencySuppressions": [] } -} \ No newline at end of file +} diff --git a/it/csharp/dotnet.csproj b/it/csharp/dotnet.csproj index f2cf772a79..d0f857cfca 100644 --- a/it/csharp/dotnet.csproj +++ b/it/csharp/dotnet.csproj @@ -10,13 +10,13 @@ - - - - - - - + + + + + + + diff --git a/it/go/basic/go.mod b/it/go/basic/go.mod index 477db903f4..a94128c3e7 100644 --- a/it/go/basic/go.mod +++ b/it/go/basic/go.mod @@ -1,6 +1,6 @@ module integrationtest -go 1.20 +go 1.23 require ( github.com/microsoft/kiota-abstractions-go v1.5.0 diff --git a/it/go/go.mod b/it/go/go.mod index 8391d2ec90..2f7bb9179f 100644 --- a/it/go/go.mod +++ b/it/go/go.mod @@ -1,39 +1,40 @@ module integrationtest -go 1.20 +go 1.23 require ( github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 - github.com/microsoft/kiota-abstractions-go v1.7.0 + github.com/microsoft/kiota-abstractions-go v1.8.1 github.com/microsoft/kiota-authentication-azure-go v1.1.0 - github.com/microsoft/kiota-http-go v1.4.5 + github.com/microsoft/kiota-http-go v1.4.7 github.com/microsoft/kiota-serialization-form-go v1.0.0 - github.com/microsoft/kiota-serialization-json-go v1.0.8 + github.com/microsoft/kiota-serialization-json-go v1.0.9 github.com/microsoft/kiota-serialization-multipart-go v1.0.0 github.com/microsoft/kiota-serialization-text-go v1.0.0 ) require ( - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect - github.com/cjlapao/common-go v0.0.39 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 // indirect + github.com/cjlapao/common-go v0.0.41 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang-jwt/jwt/v5 v5.2.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/std-uritemplate/std-uritemplate/go v0.0.57 // indirect - github.com/stretchr/testify v1.9.0 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect - golang.org/x/crypto v0.27.0 // indirect - golang.org/x/net v0.29.0 // indirect - golang.org/x/sys v0.25.0 // indirect - golang.org/x/text v0.18.0 // indirect + github.com/std-uritemplate/std-uritemplate/go/v2 v2.0.1 // indirect + github.com/stretchr/testify v1.10.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.33.0 // indirect + go.opentelemetry.io/otel/metric v1.33.0 // indirect + go.opentelemetry.io/otel/trace v1.33.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.33.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/it/go/go.sum b/it/go/go.sum index 6341de25a3..3c52659b4c 100644 --- a/it/go/go.sum +++ b/it/go/go.sum @@ -1,44 +1,52 @@ -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2 h1:kYRSnvJju5gYVyhkij+RTJ/VR6QIUaCfWeaFm2ycsjQ= +github.com/AzureAD/microsoft-authentication-library-for-go v1.3.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= -github.com/cjlapao/common-go v0.0.39 h1:bAAUrj2B9v0kMzbAOhzjSmiyDy+rd56r2sy7oEiQLlA= -github.com/cjlapao/common-go v0.0.39/go.mod h1:M3dzazLjTjEtZJbbxoA5ZDiGCiHmpwqW9l4UWaddwOA= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cjlapao/common-go v0.0.41 h1:j30UKZJWVWIllJ66x3EOslJvIk/VjkyenrhEcH64dGM= +github.com/cjlapao/common-go v0.0.41/go.mod h1:ao5wEp0hYMNehJiHoarSjc5dKK5wi4LvnwjXaC2SxUI= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/microsoft/kiota-abstractions-go v1.7.0 h1:/0OKSSEe94Z1qgpcGE7ZFI9P+4iAnsDQo9v9UOk+R8E= -github.com/microsoft/kiota-abstractions-go v1.7.0/go.mod h1:FI1I2OHg0E7bK5t8DPnw+9C/CHVyLP6XeqDBT+95pTE= +github.com/microsoft/kiota-abstractions-go v1.8.1 h1:0gtK3KERmbKYm5AxJLZ8WPlNR9eACUGWuofFIa01PnA= +github.com/microsoft/kiota-abstractions-go v1.8.1/go.mod h1:YO2QCJyNM9wzvlgGLepw6s9XrPgNHODOYGVDCqQWdLI= github.com/microsoft/kiota-authentication-azure-go v1.1.0 h1:HudH57Enel9zFQ4TEaJw6lMiyZ5RbBdrRHwdU0NP2RY= github.com/microsoft/kiota-authentication-azure-go v1.1.0/go.mod h1:zfPFOiLdEqM77Hua5B/2vpcXrVaGqSWjHSRzlvAWEgc= -github.com/microsoft/kiota-http-go v1.4.5 h1:BrI9TZ0cWiU1ucP5oSWR6UmP2vR3PaKbQ61TQ/qM5cM= -github.com/microsoft/kiota-http-go v1.4.5/go.mod h1:Kup5nMDD3a9sjdgRKHCqZWqtrv3FbprjcPaGjLR6FzM= +github.com/microsoft/kiota-http-go v1.4.7 h1:yFmwYLlCCkeYGDZyvBgfoHWAadOwmg4XQyx35CBkwU8= +github.com/microsoft/kiota-http-go v1.4.7/go.mod h1:Kup5nMDD3a9sjdgRKHCqZWqtrv3FbprjcPaGjLR6FzM= github.com/microsoft/kiota-serialization-form-go v1.0.0 h1:UNdrkMnLFqUCccQZerKjblsyVgifS11b3WCx+eFEsAI= github.com/microsoft/kiota-serialization-form-go v1.0.0/go.mod h1:h4mQOO6KVTNciMF6azi1J9QB19ujSw3ULKcSNyXXOMA= -github.com/microsoft/kiota-serialization-json-go v1.0.8 h1:+aViv9k6wqaw1Fx6P49fl5GIB1hN3b6CG0McNTcUYBc= -github.com/microsoft/kiota-serialization-json-go v1.0.8/go.mod h1:O8+v11U0EUwHlCz7hrW38KxDmdhKAHfv4Q89uvsBalY= +github.com/microsoft/kiota-serialization-json-go v1.0.9 h1:lJivec0G0tI6T8McBTnucyyYXczXytwcu1pt0UjWSBY= +github.com/microsoft/kiota-serialization-json-go v1.0.9/go.mod h1:AxrS/Gbmr8y/hIp2pJcpTup/2wCE8ED+VEXkf/9xKb4= github.com/microsoft/kiota-serialization-multipart-go v1.0.0 h1:3O5sb5Zj+moLBiJympbXNaeV07K0d46IfuEd5v9+pBs= github.com/microsoft/kiota-serialization-multipart-go v1.0.0/go.mod h1:yauLeBTpANk4L03XD985akNysG24SnRJGaveZf+p4so= github.com/microsoft/kiota-serialization-text-go v1.0.0 h1:XOaRhAXy+g8ZVpcq7x7a0jlETWnWrEum0RhmbYrTFnA= @@ -48,27 +56,32 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/std-uritemplate/std-uritemplate/go v0.0.57 h1:GHGjptrsmazP4IVDlUprssiEf9ESVkbjx15xQXXzvq4= -github.com/std-uritemplate/std-uritemplate/go v0.0.57/go.mod h1:rG/bqh/ThY4xE5de7Rap3vaDkYUT76B0GPJ0loYeTTc= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/std-uritemplate/std-uritemplate/go/v2 v2.0.1 h1:/m2cTZHpqgofDsrwPqsASI6fSNMNhb+9EmUYtHEV2Uk= +github.com/std-uritemplate/std-uritemplate/go/v2 v2.0.1/go.mod h1:Z5KcoM0YLC7INlNhEezeIZ0TZNYf7WSNO0Lvah4DSeQ= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= +go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= +go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= +go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= +go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= +go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/it/java/pom.xml b/it/java/pom.xml index 0647c23e1b..3b0543615e 100644 --- a/it/java/pom.xml +++ b/it/java/pom.xml @@ -15,7 +15,7 @@ UTF-8 UTF-8 - 1.7.0 + 1.8.2 diff --git a/it/php/phpstan.neon b/it/php/phpstan.neon index 11ffe2a09e..8af9a44026 100644 --- a/it/php/phpstan.neon +++ b/it/php/phpstan.neon @@ -7,4 +7,4 @@ parameters: - src ignoreErrors: - '#Parameter [\w\W]+ \$errorMappings of method [\w\\]+RequestAdapter::send[\w]+\(\) expects [\w\W\s]+ given\.#' - - '#getFieldDeserializers\(\) should return array\ but returns array\{[\d]+\: Closure\(Microsoft\\Kiota\\Abstractions\\Serialization\\ParseNode\)\: void.+#' + - '#getFieldDeserializers\(\) should return array\ but returns array\{.+\: Closure\(Microsoft\\Kiota\\Abstractions\\Serialization\\ParseNode\)\: void.+#' diff --git a/it/python/requirements-dev.txt b/it/python/requirements-dev.txt index d10b46f07a..249324cc9e 100644 --- a/it/python/requirements-dev.txt +++ b/it/python/requirements-dev.txt @@ -1,18 +1,18 @@ -i https://pypi.org/simple -astroid==3.3.5 ; python_full_version >= '3.7.2' +astroid==3.3.8 ; python_full_version >= '3.7.2' -certifi==2024.8.30 ; python_version >= '3.6' +certifi==2024.12.14 ; python_version >= '3.6' -charset-normalizer==3.4.0 ; python_full_version >= '3.7.0' +charset-normalizer==3.4.1 ; python_full_version >= '3.7.0' colorama==0.4.6 ; sys_platform == 'win32' -dill==0.3.6 ; python_version < '3.11' +dill==0.3.9 ; python_version < '3.11' docutils==0.21.2 ; python_version >= '3.7' -exceptiongroup==1.1.1 ; python_version < '3.11' +exceptiongroup==1.2.2 ; python_version < '3.11' flit==3.10.1 @@ -30,7 +30,7 @@ lazy-object-proxy==1.10.0 ; python_version >= '3.7' mccabe==0.7.0 ; python_version >= '3.6' -mypy==1.13.0 +mypy==1.14.1 mypy-extensions==1.0.0 ; python_version >= '3.5' @@ -40,17 +40,17 @@ platformdirs==4.3.6 ; python_version >= '3.7' pluggy==1.5.0 ; python_version >= '3.7' -pylint==3.3.1 +pylint==3.3.3 -pytest==8.3.3 +pytest==8.3.4 -pytest-asyncio==0.24.0 +pytest-asyncio==0.25.1 requests==2.32.3 ; python_version >= '3.7' toml==0.10.2 -tomli==2.0.1 ; python_version < '3.11' +tomli==2.2.1 ; python_version < '3.11' tomli-w==1.1.0 ; python_version >= '3.7' @@ -58,23 +58,23 @@ tomlkit==0.13.2 ; python_version >= '3.7' typing-extensions==4.12.2 ; python_version >= '3.7' -urllib3==2.2.3 ; python_version >= '3.7' +urllib3==2.3.0 ; python_version >= '3.7' -wrapt==1.15.0 ; python_version < '3.11' +wrapt==1.17.0 ; python_version < '3.11' -yapf==0.40.2 +yapf==0.43.0 zipp==3.21.0 ; python_version >= '3.7' -aiohttp==3.10.10 ; python_version >= '3.6' +aiohttp==3.11.11 ; python_version >= '3.6' -aiosignal==1.3.1 ; python_version >= '3.7' +aiosignal==1.3.2 ; python_version >= '3.7' -anyio==4.6.2.post1 ; python_version >= '3.7' +anyio==4.8.0 ; python_version >= '3.7' async-timeout==5.0.1 ; python_version >= '3.6' -attrs==24.2.0 ; python_version >= '3.7' +attrs==24.3.0 ; python_version >= '3.7' azure-core==1.32.0 ; python_version >= '3.7' @@ -82,7 +82,7 @@ azure-identity==1.19.0 cffi==1.17.1 -cryptography==43.0.3 ; python_version >= '3.7' +cryptography==44.0.0 ; python_version >= '3.7' frozenlist==1.5.0 ; python_version >= '3.7' @@ -92,37 +92,37 @@ h2==4.1.0 hpack==4.0.0 ; python_full_version >= '3.6.1' -httpcore==1.0.6 ; python_version >= '3.7' +httpcore==1.0.7 ; python_version >= '3.7' -httpx[http2]==0.27.2 +httpx[http2]==0.28.1 hyperframe==6.0.1 ; python_full_version >= '3.6.1' -microsoft-kiota-abstractions==1.6.1 +microsoft-kiota-abstractions==1.6.8 -microsoft-kiota-authentication-azure==1.6.1 +microsoft-kiota-authentication-azure==1.6.8 -microsoft-kiota-http==1.6.1 +microsoft-kiota-http==1.6.8 -microsoft-kiota-serialization-json==1.6.1 +microsoft-kiota-serialization-json==1.6.8 -microsoft-kiota-serialization-text==1.6.1 +microsoft-kiota-serialization-text==1.6.8 -microsoft-kiota-serialization-form==1.6.1 +microsoft-kiota-serialization-form==1.6.8 -microsoft-kiota-serialization-multipart==1.6.1 +microsoft-kiota-serialization-multipart==1.6.8 -msal==1.31.0 +msal==1.31.1 msal-extensions==1.2.0 multidict==6.1.0 ; python_version >= '3.7' -portalocker==2.10.1 ; python_version >= '3.5' and platform_system == 'Windows' +portalocker==3.1.1 ; python_version >= '3.5' and platform_system == 'Windows' pycparser==2.22 -pyjwt[crypto]==2.9.0 ; python_version >= '3.7' +pyjwt[crypto]==2.10.1 ; python_version >= '3.7' python-dateutil==2.9.0.post0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2' @@ -130,11 +130,11 @@ pywin32==308 ; platform_system == 'Windows' rfc3986[idna2008]==2.0.0 -six==1.16.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2' +six==1.17.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2' sniffio==1.3.1 ; python_version >= '3.7' uritemplate==4.1.1 ; python_version >= '3.6' -yarl==1.17.1 ; python_version >= '3.7' +yarl==1.18.3 ; python_version >= '3.7' diff --git a/it/typescript/package-lock.json b/it/typescript/package-lock.json index 85a1aede3e..70a26854fc 100644 --- a/it/typescript/package-lock.json +++ b/it/typescript/package-lock.json @@ -10,27 +10,27 @@ "license": "MIT", "dependencies": { "@azure/identity": "^4.5.0", - "@microsoft/kiota-abstractions": "^1.0.0-preview.74", - "@microsoft/kiota-authentication-azure": "^1.0.0-preview.74", - "@microsoft/kiota-http-fetchlibrary": "^1.0.0-preview.74", - "@microsoft/kiota-serialization-form": "^1.0.0-preview.74", - "@microsoft/kiota-serialization-json": "^1.0.0-preview.74", - "@microsoft/kiota-serialization-multipart": "^1.0.0-preview.74", - "@microsoft/kiota-serialization-text": "^1.0.0-preview.74", + "@microsoft/kiota-abstractions": "^1.0.0-preview.78", + "@microsoft/kiota-authentication-azure": "^1.0.0-preview.78", + "@microsoft/kiota-http-fetchlibrary": "^1.0.0-preview.78", + "@microsoft/kiota-serialization-form": "^1.0.0-preview.78", + "@microsoft/kiota-serialization-json": "^1.0.0-preview.78", + "@microsoft/kiota-serialization-multipart": "^1.0.0-preview.78", + "@microsoft/kiota-serialization-text": "^1.0.0-preview.78", "express": "^5.0.1", "node-fetch": "^2.7.0" }, "devDependencies": { "@es-exec/esbuild-plugin-start": "^0.0.5", - "@stylistic/eslint-plugin-ts": "^2.10.1", - "@types/node": "^22.9.0", - "@typescript-eslint/eslint-plugin": "^8.13.0", - "@typescript-eslint/parser": "^8.13.0", - "esbuild": "^0.24.0", - "eslint": "^9.14.0", + "@stylistic/eslint-plugin-ts": "^2.12.1", + "@types/node": "^22.10.5", + "@typescript-eslint/eslint-plugin": "^8.19.1", + "@typescript-eslint/parser": "^8.19.1", + "esbuild": "^0.24.2", + "eslint": "^9.17.0", "eslint-config-prettier": "^9.1.0", "minimist": "^1.2.8", - "prettier": "^3.3.3", + "prettier": "^3.4.2", "typescript": "^4.9.5" } }, @@ -221,9 +221,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz", - "integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", "cpu": [ "ppc64" ], @@ -237,9 +237,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz", - "integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", "cpu": [ "arm" ], @@ -253,9 +253,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz", - "integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", "cpu": [ "arm64" ], @@ -269,9 +269,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz", - "integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", "cpu": [ "x64" ], @@ -285,9 +285,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz", - "integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", "cpu": [ "arm64" ], @@ -301,9 +301,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz", - "integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", "cpu": [ "x64" ], @@ -317,9 +317,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz", - "integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", "cpu": [ "arm64" ], @@ -333,9 +333,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz", - "integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", "cpu": [ "x64" ], @@ -349,9 +349,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz", - "integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", "cpu": [ "arm" ], @@ -365,9 +365,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz", - "integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", "cpu": [ "arm64" ], @@ -381,9 +381,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz", - "integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", "cpu": [ "ia32" ], @@ -397,9 +397,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz", - "integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", "cpu": [ "loong64" ], @@ -413,9 +413,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz", - "integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", "cpu": [ "mips64el" ], @@ -429,9 +429,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz", - "integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", "cpu": [ "ppc64" ], @@ -445,9 +445,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz", - "integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", "cpu": [ "riscv64" ], @@ -461,9 +461,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz", - "integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", "cpu": [ "s390x" ], @@ -477,9 +477,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz", - "integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", "cpu": [ "x64" ], @@ -492,10 +492,26 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz", - "integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", "cpu": [ "x64" ], @@ -509,9 +525,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz", - "integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", "cpu": [ "arm64" ], @@ -525,9 +541,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz", - "integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", "cpu": [ "x64" ], @@ -541,9 +557,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz", - "integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", "cpu": [ "x64" ], @@ -557,9 +573,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz", - "integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", "cpu": [ "arm64" ], @@ -573,9 +589,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz", - "integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", "cpu": [ "ia32" ], @@ -589,9 +605,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz", - "integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", "cpu": [ "x64" ], @@ -629,9 +645,9 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", "dev": true, "dependencies": { "@eslint/object-schema": "^2.1.4", @@ -643,18 +659,18 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -675,9 +691,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -693,9 +709,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz", - "integrity": "sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "dev": true, "dependencies": { "levn": "^0.4.1" @@ -753,9 +769,9 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.0.tgz", - "integrity": "sha512-xnRgu9DxZbkWak/te3fcytNyp8MTbuiZIaueg2rgEvBuN55n04nwLYLU9TX/VVlusc9L2ZNXi99nUFNkHXtr5g==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, "engines": { "node": ">=18.18" @@ -766,12 +782,12 @@ } }, "node_modules/@microsoft/kiota-abstractions": { - "version": "1.0.0-preview.74", - "resolved": "https://registry.npmjs.org/@microsoft/kiota-abstractions/-/kiota-abstractions-1.0.0-preview.74.tgz", - "integrity": "sha512-pzn91PIvWXamLZ0z9wm6V5AORF8TUH/oBYAhEwjO0qEBp7daftU3GAAlo5pTJnA1jymRBBe21HRIVLFEMOEmPw==", + "version": "1.0.0-preview.78", + "resolved": "https://registry.npmjs.org/@microsoft/kiota-abstractions/-/kiota-abstractions-1.0.0-preview.78.tgz", + "integrity": "sha512-xQDr3zG/i7rpwoqHLOD4zYfq4Aw39LcZoqOBN0B7m7L35v5dEPR6f7a6d0MJ4AehBqQokrIOpU/atFcG0waZTA==", "dependencies": { "@opentelemetry/api": "^1.7.0", - "@std-uritemplate/std-uritemplate": "^1.0.1", + "@std-uritemplate/std-uritemplate": "^2.0.0", "tinyduration": "^3.3.0", "tslib": "^2.6.2", "uuid": "^11.0.2" @@ -790,59 +806,59 @@ } }, "node_modules/@microsoft/kiota-authentication-azure": { - "version": "1.0.0-preview.74", - "resolved": "https://registry.npmjs.org/@microsoft/kiota-authentication-azure/-/kiota-authentication-azure-1.0.0-preview.74.tgz", - "integrity": "sha512-QxrJQ1kIiwJ6mOisjGdCHtiSIs0YZLiljVDxsgyg39N1mP3R0DLpufOdAPhW+AyVDojZKPYrdj8LepKY32IyRQ==", + "version": "1.0.0-preview.78", + "resolved": "https://registry.npmjs.org/@microsoft/kiota-authentication-azure/-/kiota-authentication-azure-1.0.0-preview.78.tgz", + "integrity": "sha512-iE67HXY6OrDHZPe3esnBnqsqhFrQj/jc2vpNjIcBLG6BwWU7LHrnbhKa3zRVN+XlQBkUvajAyRqRRV0zKa7aKA==", "dependencies": { "@azure/core-auth": "^1.5.0", - "@microsoft/kiota-abstractions": "^1.0.0-preview.74", + "@microsoft/kiota-abstractions": "^1.0.0-preview.78", "@opentelemetry/api": "^1.7.0", "tslib": "^2.6.2" } }, "node_modules/@microsoft/kiota-http-fetchlibrary": { - "version": "1.0.0-preview.74", - "resolved": "https://registry.npmjs.org/@microsoft/kiota-http-fetchlibrary/-/kiota-http-fetchlibrary-1.0.0-preview.74.tgz", - "integrity": "sha512-jEJbr+m64tA8KhwIyPEwPH/xzkNX8iXLT9oipam0UinIFEviFTh1be6QUEhMO0O/ZABVHRzbz433jlQTR3mTAQ==", + "version": "1.0.0-preview.78", + "resolved": "https://registry.npmjs.org/@microsoft/kiota-http-fetchlibrary/-/kiota-http-fetchlibrary-1.0.0-preview.78.tgz", + "integrity": "sha512-eJwwWlwna0QiB3+g6GPmdoZRShWOJh49/Ngp+q+rFQX2t2vZ1nEyagcFi9A5tV4f/qhsmrbXxRp/lmqZNl8i6Q==", "dependencies": { - "@microsoft/kiota-abstractions": "^1.0.0-preview.74", + "@microsoft/kiota-abstractions": "^1.0.0-preview.78", "@opentelemetry/api": "^1.7.0", "tslib": "^2.6.2" } }, "node_modules/@microsoft/kiota-serialization-form": { - "version": "1.0.0-preview.74", - "resolved": "https://registry.npmjs.org/@microsoft/kiota-serialization-form/-/kiota-serialization-form-1.0.0-preview.74.tgz", - "integrity": "sha512-KNjwVNG0UHWKO8vLEq6KUSjObKdIhpY6wM7J6F/pm5brh4PVGPljsTE3GvY4YPcXjUSuBvGTmPKWV2c+zCmNqQ==", + "version": "1.0.0-preview.78", + "resolved": "https://registry.npmjs.org/@microsoft/kiota-serialization-form/-/kiota-serialization-form-1.0.0-preview.78.tgz", + "integrity": "sha512-MeHAexViBpl8x82ukA1ffBMlDEap3J1v5ZJMUD1K+GKGX8ifj4jlznlYcmbIQqWZRW8+yUrtqKjQNAsCpJL/gQ==", "dependencies": { - "@microsoft/kiota-abstractions": "^1.0.0-preview.74", + "@microsoft/kiota-abstractions": "^1.0.0-preview.78", "tslib": "^2.6.2" } }, "node_modules/@microsoft/kiota-serialization-json": { - "version": "1.0.0-preview.74", - "resolved": "https://registry.npmjs.org/@microsoft/kiota-serialization-json/-/kiota-serialization-json-1.0.0-preview.74.tgz", - "integrity": "sha512-faXKOBEwDxGCkJNFV7zGQUia7tj964QVPtmLQ4t8oHv7Eg0uSDga7LHoiL+CqYjQsYSNdzlOXSpLtwYp7vkk+A==", + "version": "1.0.0-preview.78", + "resolved": "https://registry.npmjs.org/@microsoft/kiota-serialization-json/-/kiota-serialization-json-1.0.0-preview.78.tgz", + "integrity": "sha512-Hrk6DrrrcyDiTjxOxvS7J8SOVEUScyyBIPOtXpSPJAeoeUmoQ7UGyDu7NzLqPzVCIo+B2Ygxct3tdc5ZDoh4ng==", "dependencies": { - "@microsoft/kiota-abstractions": "^1.0.0-preview.74", + "@microsoft/kiota-abstractions": "^1.0.0-preview.78", "tslib": "^2.6.2" } }, "node_modules/@microsoft/kiota-serialization-multipart": { - "version": "1.0.0-preview.74", - "resolved": "https://registry.npmjs.org/@microsoft/kiota-serialization-multipart/-/kiota-serialization-multipart-1.0.0-preview.74.tgz", - "integrity": "sha512-r5pacUaynVn5p3tdD41ifRXXBQKq36/FCev3sJLeHOH6IA4lcRcVwoI9DZtXZrncyuqZ2rPeEdLIgBgjYSra4Q==", + "version": "1.0.0-preview.78", + "resolved": "https://registry.npmjs.org/@microsoft/kiota-serialization-multipart/-/kiota-serialization-multipart-1.0.0-preview.78.tgz", + "integrity": "sha512-CpVKtPesh2wgMSF1cJoBus+AZuaOoofaIb9YkkdPfm+L+PH/3cFCposQ+a/jgF9f4FCTe2SxxCgiP/gzh/aRdQ==", "dependencies": { - "@microsoft/kiota-abstractions": "^1.0.0-preview.74", + "@microsoft/kiota-abstractions": "^1.0.0-preview.78", "tslib": "^2.6.2" } }, "node_modules/@microsoft/kiota-serialization-text": { - "version": "1.0.0-preview.74", - "resolved": "https://registry.npmjs.org/@microsoft/kiota-serialization-text/-/kiota-serialization-text-1.0.0-preview.74.tgz", - "integrity": "sha512-A3RqoNymLyhH8yG4GbhVma/BYJ1ivLI28Y9yF895NKoIou8nGegsF4qseJn7T+5aY+T3Hv3WvU/gcdHE/qZ2Pg==", + "version": "1.0.0-preview.78", + "resolved": "https://registry.npmjs.org/@microsoft/kiota-serialization-text/-/kiota-serialization-text-1.0.0-preview.78.tgz", + "integrity": "sha512-TlAF4YHwyn0CeGh1snLlB/9PeGl5+K/9OLko9S99QWIbeIlGJnU4hrJFfIBK7JIqLFZw1pPuYMVe3vh5xDlxCQ==", "dependencies": { - "@microsoft/kiota-abstractions": "^1.0.0-preview.74", + "@microsoft/kiota-abstractions": "^1.0.0-preview.78", "tslib": "^2.6.2" } }, @@ -890,17 +906,18 @@ } }, "node_modules/@std-uritemplate/std-uritemplate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@std-uritemplate/std-uritemplate/-/std-uritemplate-1.0.2.tgz", - "integrity": "sha512-35k/Nn+wlqkOf9AxIlhOA19mndrUMDspRuV3lO/9IgqKk0W7b8LwuWup5bGt4wZ1sCZij/lDTQMTY9WKTKrusg==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@std-uritemplate/std-uritemplate/-/std-uritemplate-2.0.1.tgz", + "integrity": "sha512-HC5kiXCa7Mxrv7SI7qH4ECfC1H+vFG15COBtX8aUur8EGEWK17RH3QVyBxtyjUXE448O4fGhQHh3kirEvPGWjw==" }, "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.10.1.tgz", - "integrity": "sha512-XmXcixLPYfW0Z4Nf2ChnQ7CnfALNy/5gwNh22POiy64xreVYtiag4+yxN2SBEalEfoOAwDnqwDKam7e7XeoKTA==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.12.1.tgz", + "integrity": "sha512-Xx1NIioeW6LLlOfq5L/dLSrUXvi6q80UXDNbn/rXjKCzFT4a8wKwtp1q25kssdr1JEXI9a6tOHwFsh4Em+MoGg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^8.12.2", + "@typescript-eslint/utils": "^8.13.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0" }, @@ -936,29 +953,29 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", + "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", "dev": true, "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.13.0.tgz", - "integrity": "sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz", + "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/type-utils": "8.13.0", - "@typescript-eslint/utils": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/type-utils": "8.19.1", + "@typescript-eslint/utils": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -969,24 +986,20 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.13.0.tgz", - "integrity": "sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz", + "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "debug": "^4.3.4" }, "engines": { @@ -997,22 +1010,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz", - "integrity": "sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", + "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0" + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1023,15 +1032,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.13.0.tgz", - "integrity": "sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz", + "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/utils": "8.13.0", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/utils": "8.19.1", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1040,16 +1049,15 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.13.0.tgz", - "integrity": "sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", + "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", "dev": true, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1060,19 +1068,19 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz", - "integrity": "sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", + "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1081,10 +1089,8 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { @@ -1112,15 +1118,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.13.0.tgz", - "integrity": "sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz", + "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0" + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1130,17 +1136,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz", - "integrity": "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", + "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "8.13.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.19.1", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1150,6 +1157,18 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -1454,9 +1473,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -1576,9 +1595,9 @@ } }, "node_modules/esbuild": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", - "integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==", + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", "dev": true, "hasInstallScript": true, "bin": { @@ -1588,30 +1607,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.0", - "@esbuild/android-arm": "0.24.0", - "@esbuild/android-arm64": "0.24.0", - "@esbuild/android-x64": "0.24.0", - "@esbuild/darwin-arm64": "0.24.0", - "@esbuild/darwin-x64": "0.24.0", - "@esbuild/freebsd-arm64": "0.24.0", - "@esbuild/freebsd-x64": "0.24.0", - "@esbuild/linux-arm": "0.24.0", - "@esbuild/linux-arm64": "0.24.0", - "@esbuild/linux-ia32": "0.24.0", - "@esbuild/linux-loong64": "0.24.0", - "@esbuild/linux-mips64el": "0.24.0", - "@esbuild/linux-ppc64": "0.24.0", - "@esbuild/linux-riscv64": "0.24.0", - "@esbuild/linux-s390x": "0.24.0", - "@esbuild/linux-x64": "0.24.0", - "@esbuild/netbsd-x64": "0.24.0", - "@esbuild/openbsd-arm64": "0.24.0", - "@esbuild/openbsd-x64": "0.24.0", - "@esbuild/sunos-x64": "0.24.0", - "@esbuild/win32-arm64": "0.24.0", - "@esbuild/win32-ia32": "0.24.0", - "@esbuild/win32-x64": "0.24.0" + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" } }, "node_modules/escape-html": { @@ -1632,26 +1652,26 @@ } }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -1670,8 +1690,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -2812,9 +2831,9 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -3195,12 +3214,6 @@ "node": ">=8" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, "node_modules/tinyduration": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/tinyduration/-/tinyduration-3.3.0.tgz", @@ -3233,16 +3246,15 @@ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", + "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/tslib": { @@ -3289,9 +3301,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true }, "node_modules/unpipe": { diff --git a/it/typescript/package.json b/it/typescript/package.json index 9f13746244..64708174e0 100644 --- a/it/typescript/package.json +++ b/it/typescript/package.json @@ -19,26 +19,26 @@ "prettier": "./.prettierrc.json", "devDependencies": { "@es-exec/esbuild-plugin-start": "^0.0.5", - "@stylistic/eslint-plugin-ts": "^2.10.1", - "@types/node": "^22.9.0", - "@typescript-eslint/eslint-plugin": "^8.13.0", - "@typescript-eslint/parser": "^8.13.0", - "esbuild": "^0.24.0", - "eslint": "^9.14.0", + "@stylistic/eslint-plugin-ts": "^2.12.1", + "@types/node": "^22.10.5", + "@typescript-eslint/eslint-plugin": "^8.19.1", + "@typescript-eslint/parser": "^8.19.1", + "esbuild": "^0.24.2", + "eslint": "^9.17.0", "eslint-config-prettier": "^9.1.0", "minimist": "^1.2.8", - "prettier": "^3.3.3", + "prettier": "^3.4.2", "typescript": "^4.9.5" }, "dependencies": { "@azure/identity": "^4.5.0", - "@microsoft/kiota-abstractions": "^1.0.0-preview.74", - "@microsoft/kiota-authentication-azure": "^1.0.0-preview.74", - "@microsoft/kiota-http-fetchlibrary": "^1.0.0-preview.74", - "@microsoft/kiota-serialization-form": "^1.0.0-preview.74", - "@microsoft/kiota-serialization-json": "^1.0.0-preview.74", - "@microsoft/kiota-serialization-multipart": "^1.0.0-preview.74", - "@microsoft/kiota-serialization-text": "^1.0.0-preview.74", + "@microsoft/kiota-abstractions": "^1.0.0-preview.78", + "@microsoft/kiota-authentication-azure": "^1.0.0-preview.78", + "@microsoft/kiota-http-fetchlibrary": "^1.0.0-preview.78", + "@microsoft/kiota-serialization-form": "^1.0.0-preview.78", + "@microsoft/kiota-serialization-json": "^1.0.0-preview.78", + "@microsoft/kiota-serialization-multipart": "^1.0.0-preview.78", + "@microsoft/kiota-serialization-text": "^1.0.0-preview.78", "express": "^5.0.1", "node-fetch": "^2.7.0" } diff --git a/scripts/check-translations.ps1 b/scripts/check-translations.ps1 new file mode 100644 index 0000000000..c606ec9c61 --- /dev/null +++ b/scripts/check-translations.ps1 @@ -0,0 +1,83 @@ +# Step 1: Find all instances of vscode.l10n.t() and extract the strings from .ts and .tsx files +$withParamsPattern = 'vscode\.l10n\.t\(["''`](.+?)["''`],' +Get-ChildItem -Path vscode/microsoft-kiota/src -Recurse -Include *.ts, *.tsx | +Select-String -Pattern $withParamsPattern | +ForEach-Object { $_.Matches.Groups[1].Value } | +Sort-Object | +Get-Unique | +Out-File -FilePath "strings_with_params.txt" + +$withoutParamsPattern = 'vscode\.l10n\.t\(["' + "`'" + '`]([^"' + "`'" + '`]+)["' + "`'" + '`]\)' +Get-ChildItem -Path vscode/microsoft-kiota/src -Recurse -Include *.ts, *.tsx | +Select-String -Pattern $withoutParamsPattern | +ForEach-Object { $_.Matches.Groups[1].Value } | +Sort-Object | +Get-Unique | +Out-File -FilePath "strings_without_params.txt" + +Get-Content strings_with_params.txt, strings_without_params.txt | +Sort-Object | +Get-Unique | +Out-File -FilePath "strings.txt" + +# Step 2: Check translation files in the l10n folder +$results = @() +foreach ($file in Get-ChildItem -Path "vscode/microsoft-kiota/l10n" -Filter bundle.l10n.*.json -Recurse) { + $translations = Get-Content $file.FullName | + Select-String -Pattern '"[^"]+"' | + ForEach-Object { $_.Matches.Groups[0].Value.Trim('"') } | + Sort-Object + $missing = Compare-Object (Get-Content "strings.txt") $translations -PassThru | + Where-Object { $_.SideIndicator -eq "<=" } + + if ($missing) { + $untranslatedItems = $missing | ForEach-Object { "
  • $_
  • " } + $results += [PSCustomObject]@{ + "LanguageFile" = "$($file.Name)" + "Count" = "$($untranslatedItems.Count) found" + "UntranslatedStrings" = "
      $($untranslatedItems -join "`n")
    " + } + } +} + +# Create the HTML table +$htmlTable = @" + + + + + + +

    Untranslated Strings

    + + + + + +"@ +foreach ($result in $results) { + $htmlTable += "" +} +$htmlTable += @" +
    Language FileUntranslated Strings
    $($result.LanguageFile) ($($result.Count))$($result.UntranslatedStrings)
    + + +"@ +$htmlTable | Out-File -FilePath "untranslated_strings.html" + +# Output a summary table to the workflow log +if ($results.Count -gt 0) { + Write-Host "Untranslated strings found. See untranslated_strings.html for details." -ForegroundColor Red + Write-Host "| Language File | Count |" + Write-Host "|----------------------------------------|---------|" + foreach ($result in $results) { + Write-Host "| $($result.LanguageFile) | $($result.Count) |" + } +} +else { + Write-Host "All strings have translations." -ForegroundColor Green +} diff --git a/scripts/get-release-notes.ps1 b/scripts/get-release-notes.ps1 index c3b1f02e3e..a775fca87b 100644 --- a/scripts/get-release-notes.ps1 +++ b/scripts/get-release-notes.ps1 @@ -4,12 +4,16 @@ param ( $version, [switch] [bool] - $createNotes + $createNotes, + [string] + $changelogPath = "" ) $version = $version.TrimStart("v") -$changelogPath = Join-Path -Path $PSScriptRoot -ChildPath "../CHANGELOG.md" +if ($changelogPath -eq "") { + $changelogPath = Join-Path -Path $PSScriptRoot -ChildPath "../CHANGELOG.md" +} $changeLogContent = Get-Content $changelogPath -Raw $headerLine = "## [$version]" diff --git a/scripts/get-version-from-csproj.ps1 b/scripts/get-version-from-csproj.ps1 index 2f6aaea5e9..649bab7ee2 100644 --- a/scripts/get-version-from-csproj.ps1 +++ b/scripts/get-version-from-csproj.ps1 @@ -1,9 +1,13 @@ param ( [switch] [bool] - $isGHA + $isGHA, + [string] + $csprojPath = "" ) -$csprojPath = Join-Path $PSScriptRoot "../src/kiota/kiota.csproj" +if ($csprojPath -eq "") { + $csprojPath = Join-Path $PSScriptRoot "../src/kiota/kiota.csproj" +} $xml = [Xml] (Get-Content $csprojPath) $version = $xml.Project.PropertyGroup.VersionPrefix[0] Write-Output "csproj version is $version" diff --git a/src/Kiota.Builder/Extensions/IListExtensions.cs b/src/Kiota.Builder/Extensions/IListExtensions.cs new file mode 100644 index 0000000000..ec2aed7711 --- /dev/null +++ b/src/Kiota.Builder/Extensions/IListExtensions.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; + +namespace Kiota.Builder.Extensions; + +public static class IListExtensions +{ + /// + /// Returns the only element of this list when it has count of exactly 1 + /// + /// The contained item type. + /// The items. + /// The only element or null. + internal static T? OnlyOneOrDefault(this IList items) => + items.Count == 1 ? items[0] : default; + + /// + /// Adds the provided to this list. + /// + /// The contained item type. + /// The items. + /// The values to add. + internal static void AddRange(this IList items, IEnumerable values) + { + foreach (var item in values) + { + items.Add(item); + } + } +} diff --git a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs index c5ed4b24e9..ec9d9d2f6a 100644 --- a/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs +++ b/src/Kiota.Builder/Extensions/OpenApiSchemaExtensions.cs @@ -68,16 +68,20 @@ public static bool HasAnyProperty(this OpenApiSchema? schema) { return schema?.Properties is { Count: > 0 }; } - public static bool IsInclusiveUnion(this OpenApiSchema? schema) + public static bool IsInclusiveUnion(this OpenApiSchema? schema, uint exclusiveMinimumNumberOfEntries = 1) { - return schema?.AnyOf?.Count(static x => IsSemanticallyMeaningful(x, true)) > 1; + return schema?.AnyOf?.Count(static x => IsSemanticallyMeaningful(x, true)) > exclusiveMinimumNumberOfEntries; // so we don't consider any of object/nullable as a union type } public static bool IsInherited(this OpenApiSchema? schema) { if (schema is null) return false; - var meaningfulMemberSchemas = schema.AllOf.FlattenSchemaIfRequired(static x => x.AllOf).Where(static x => x.IsSemanticallyMeaningful(ignoreEnums: true, ignoreArrays: true, ignoreType: true)).ToArray(); + var meaningfulMemberSchemas = schema.AllOf.FlattenSchemaIfRequired(static x => x.AllOf) + .Where(static x => x.IsSemanticallyMeaningful(ignoreEnums: true, ignoreArrays: true, ignoreType: true)) + // the next line ensures the meaningful schema are objects as it won't make sense inheriting from a primitive despite it being meaningful. + .Where(static x => string.IsNullOrEmpty(x.Reference?.Id) || string.IsNullOrEmpty(x.Type) || "object".Equals(x.Type, StringComparison.OrdinalIgnoreCase)) + .ToArray(); var isRootSchemaMeaningful = schema.IsSemanticallyMeaningful(ignoreEnums: true, ignoreArrays: true, ignoreType: true); return meaningfulMemberSchemas.Count(static x => !string.IsNullOrEmpty(x.Reference?.Id)) == 1 && (meaningfulMemberSchemas.Count(static x => string.IsNullOrEmpty(x.Reference?.Id)) == 1 || @@ -89,6 +93,58 @@ public static bool IsInherited(this OpenApiSchema? schema) return schema.MergeIntersectionSchemaEntries(schemasToExclude, true, filter); } + internal static OpenApiSchema? MergeInclusiveUnionSchemaEntries(this OpenApiSchema? schema) + { + if (schema is null || !schema.IsInclusiveUnion(0)) return null; + var result = new OpenApiSchema(schema); + result.AnyOf.Clear(); + result.TryAddProperties(schema.AnyOf.SelectMany(static x => x.Properties)); + return result; + } + + internal static OpenApiSchema? MergeExclusiveUnionSchemaEntries(this OpenApiSchema? schema) + { + if (schema is null || !schema.IsExclusiveUnion(0)) return null; + var result = new OpenApiSchema(schema); + result.OneOf.Clear(); + result.TryAddProperties(schema.OneOf.SelectMany(static x => x.Properties)); + return result; + } + + internal static OpenApiSchema? MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries(this OpenApiSchema? schema) + { + if (schema is not null + && schema.IsInclusiveUnion(0) + && schema.AnyOf.OnlyOneOrDefault() is OpenApiSchema subSchema + && (subSchema.IsInherited() || subSchema.IsIntersection())) + { + var result = new OpenApiSchema(schema); + result.AnyOf.Clear(); + result.TryAddProperties(subSchema.Properties); + result.AllOf.AddRange(subSchema.AllOf); + return result; + } + + return null; + } + + internal static OpenApiSchema? MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries(this OpenApiSchema? schema) + { + if (schema is not null + && schema.IsExclusiveUnion(0) + && schema.OneOf.OnlyOneOrDefault() is OpenApiSchema subSchema + && (subSchema.IsInherited() || subSchema.IsIntersection())) + { + var result = new OpenApiSchema(schema); + result.OneOf.Clear(); + result.TryAddProperties(subSchema.Properties); + result.AllOf.AddRange(subSchema.AllOf); + return result; + } + + return null; + } + internal static OpenApiSchema? MergeIntersectionSchemaEntries(this OpenApiSchema? schema, HashSet? schemasToExclude = default, bool overrideIntersection = false, Func? filter = default) { if (schema is null) return null; @@ -110,11 +166,17 @@ public static bool IsInherited(this OpenApiSchema? schema) else if (discriminator.Mapping?.Any() ?? false) result.Discriminator.Mapping = discriminator.Mapping.ToDictionary(static x => x.Key, static x => x.Value); - foreach (var propertyToMerge in entriesToMerge.SelectMany(static x => x.Properties)) + result.TryAddProperties(entriesToMerge.SelectMany(static x => x.Properties)); + + return result; + } + + internal static void TryAddProperties(this OpenApiSchema schema, IEnumerable> properties) + { + foreach (var property in properties) { - result.Properties.TryAdd(propertyToMerge.Key, propertyToMerge.Value); + schema.Properties.TryAdd(property.Key, property.Value); } - return result; } public static bool IsIntersection(this OpenApiSchema? schema) @@ -123,9 +185,9 @@ public static bool IsIntersection(this OpenApiSchema? schema) return meaningfulSchemas?.Count(static x => !string.IsNullOrEmpty(x.Reference?.Id)) > 1 || meaningfulSchemas?.Count(static x => string.IsNullOrEmpty(x.Reference?.Id)) > 1; } - public static bool IsExclusiveUnion(this OpenApiSchema? schema) + public static bool IsExclusiveUnion(this OpenApiSchema? schema, uint exclusiveMinimumNumberOfEntries = 1) { - return schema?.OneOf?.Count(static x => IsSemanticallyMeaningful(x, true)) > 1; + return schema?.OneOf?.Count(static x => IsSemanticallyMeaningful(x, true)) > exclusiveMinimumNumberOfEntries; // so we don't consider one of object/nullable as a union type } private static readonly HashSet oDataTypes = new(StringComparer.OrdinalIgnoreCase) { @@ -246,19 +308,25 @@ private static IEnumerable FlattenEmptyEntries(this IEnumerable? visitedSchemas = default) { + if (schema == null) return string.Empty; + visitedSchemas ??= []; + if (visitedSchemas.Contains(schema)) + return string.Empty; + visitedSchemas.Add(schema); + if (!string.IsNullOrEmpty(schema.Discriminator?.PropertyName)) return schema.Discriminator.PropertyName; - if (schema.OneOf.Select(GetDiscriminatorPropertyName).FirstOrDefault(static x => !string.IsNullOrEmpty(x)) is string oneOfDiscriminatorPropertyName) + if (schema.OneOf.Select(x => x.GetDiscriminatorPropertyName(visitedSchemas)).FirstOrDefault(static x => !string.IsNullOrEmpty(x)) is string oneOfDiscriminatorPropertyName) return oneOfDiscriminatorPropertyName; - if (schema.AnyOf.Select(GetDiscriminatorPropertyName).FirstOrDefault(static x => !string.IsNullOrEmpty(x)) is string anyOfDiscriminatorPropertyName) + if (schema.AnyOf.Select(x => x.GetDiscriminatorPropertyName(visitedSchemas)).FirstOrDefault(static x => !string.IsNullOrEmpty(x)) is string anyOfDiscriminatorPropertyName) return anyOfDiscriminatorPropertyName; - if (schema.AllOf.Select(GetDiscriminatorPropertyName).FirstOrDefault(static x => !string.IsNullOrEmpty(x)) is string allOfDiscriminatorPropertyName) + if (schema.AllOf.Select(x => x.GetDiscriminatorPropertyName(visitedSchemas)).FirstOrDefault(static x => !string.IsNullOrEmpty(x)) is string allOfDiscriminatorPropertyName) return allOfDiscriminatorPropertyName; return string.Empty; diff --git a/src/Kiota.Builder/Kiota.Builder.csproj b/src/Kiota.Builder/Kiota.Builder.csproj index b23ec7bc4f..e3d04ad2f2 100644 --- a/src/Kiota.Builder/Kiota.Builder.csproj +++ b/src/Kiota.Builder/Kiota.Builder.csproj @@ -15,7 +15,7 @@ Microsoft.OpenApi.Kiota.Builder Microsoft.OpenApi.Kiota.Builder ./nupkg - 1.21.0 + 1.22.0 $(VersionSuffix) https://github.com/microsoft/kiota/releases @@ -35,25 +35,25 @@ $(NoWarn);CS8785;NU5048;NU5104;CA1724;CA1055;CA1848;CA1308;CA1822 - + - - - - - - - - + + + + + + + + - - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/Kiota.Builder/KiotaBuilder.cs b/src/Kiota.Builder/KiotaBuilder.cs index 193f336e99..450e392103 100644 --- a/src/Kiota.Builder/KiotaBuilder.cs +++ b/src/Kiota.Builder/KiotaBuilder.cs @@ -77,7 +77,7 @@ private async Task CleanOutputDirectoryAsync(CancellationToken cancellationToken Directory.Delete(subDir, true); await workspaceManagementService.BackupStateAsync(config.OutputPath, cancellationToken).ConfigureAwait(false); foreach (var subFile in Directory.EnumerateFiles(config.OutputPath) - .Where(x => !x.EndsWith(FileLogLogger.LogFileName, StringComparison.OrdinalIgnoreCase))) + .Where(static x => !x.EndsWith(FileLogLogger.LogFileName, StringComparison.OrdinalIgnoreCase))) File.Delete(subFile); } } @@ -243,7 +243,7 @@ public async Task GeneratePluginAsync(CancellationToken cancellationToken) throw new InvalidOperationException("The OpenAPI document and the URL tree must be loaded before generating the plugins"); // generate plugin sw.Start(); - var pluginsService = new PluginsGenerationService(openApiDocument, openApiTree, config, Directory.GetCurrentDirectory()); + var pluginsService = new PluginsGenerationService(openApiDocument, openApiTree, config, Directory.GetCurrentDirectory(), logger); await pluginsService.GenerateManifestAsync(cancellationToken).ConfigureAwait(false); StopLogAndReset(sw, $"step {++stepId} - generate plugin - took"); return stepId; @@ -958,7 +958,7 @@ x.Parent is CodeIndexer || var parentNS = x.Parent?.Parent?.Parent as CodeNamespace; CodeClass[] exceptions = x.Parent?.Parent is CodeClass parentClass ? [parentClass] : []; x.TypeDefinition = parentNS?.FindChildrenByName(x.Name) - .Except(exceptions)// the property method should not reference itself as a return type. + .Except(exceptions)// the property method should not reference itself as a return type. .MinBy(shortestNamespaceOrder); // searching down first because most request builder properties on a request builder are just sub paths on the API if (x.TypeDefinition == null) @@ -1833,6 +1833,18 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, Ope return CreateComposedModelDeclaration(currentNode, schema, operation, suffix, codeNamespace, isRequestBody, typeNameForInlineSchema); } + // type: object with single oneOf referring to inheritance or intersection + if (schema.IsObjectType() && schema.MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries() is OpenApiSchema mergedExclusiveUnionSchema) + { + return CreateModelDeclarations(currentNode, mergedExclusiveUnionSchema, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody); + } + + // type: object with single anyOf referring to inheritance or intersection + if (schema.IsObjectType() && schema.MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries() is OpenApiSchema mergedInclusiveUnionSchema) + { + return CreateModelDeclarations(currentNode, mergedInclusiveUnionSchema, operation, parentElement, suffixForInlineSchema, response, typeNameForInlineSchema, isRequestBody); + } + if (schema.IsObjectType() || schema.HasAnyProperty() || schema.IsEnum() || !string.IsNullOrEmpty(schema.AdditionalProperties?.Type)) { // no inheritance or union type, often empty definitions with only additional properties are used as property bags. @@ -1840,7 +1852,7 @@ private CodeTypeBase CreateModelDeclarations(OpenApiUrlTreeNode currentNode, Ope } if (schema.IsArray() && - !schema.Items.IsArray()) // Only handle collections of primitives and complex types. Otherwise, multi-dimensional arrays would be recursively unwrapped undesirably to lead to incorrect serialization types. + !schema.Items.IsArray()) // Only handle collections of primitives and complex types. Otherwise, multi-dimensional arrays would be recursively unwrapped undesirably to lead to incorrect serialization types. { // collections at root return CreateCollectionModelDeclaration(currentNode, schema, operation, codeNamespace, typeNameForInlineSchema, isRequestBody); @@ -1895,6 +1907,16 @@ private CodeElement AddModelDeclarationIfDoesntExist(OpenApiUrlTreeNode currentN // multiple allOf entries that do not translate to inheritance return createdClass; } + else if (schema.MergeInclusiveUnionSchemaEntries() is { } iUMergedSchema && + AddModelClass(currentNode, iUMergedSchema, declarationName, currentNamespace, currentOperation, inheritsFrom) is CodeClass uICreatedClass) + { + return uICreatedClass; + } + else if (schema.MergeExclusiveUnionSchemaEntries() is { } eUMergedSchema && + AddModelClass(currentNode, eUMergedSchema, declarationName, currentNamespace, currentOperation, inheritsFrom) is CodeClass uECreatedClass) + { + return uECreatedClass; + } return AddModelClass(currentNode, schema, declarationName, currentNamespace, currentOperation, inheritsFrom); } return existingDeclaration; @@ -2220,7 +2242,7 @@ internal static void AddDiscriminatorMethod(CodeClass newClass, string discrimin logger.LogWarning("Discriminator {ComponentKey} not found in the OpenAPI document.", componentKey); return null; } - // Call CreateModelDeclarations with isViaDiscriminator=true. This is for a special case where we always generate a base class when types are referenced via a oneOf discriminator. + // Call CreateModelDeclarations with isViaDiscriminator=true. This is for a special case where we always generate a base class when types are referenced via a oneOf discriminator. if (CreateModelDeclarations(currentNode, discriminatorSchema, currentOperation, GetShortestNamespace(currentNamespace, discriminatorSchema), string.Empty, null, string.Empty, false, true) is not CodeType result) { logger.LogWarning("Discriminator {ComponentKey} is not a valid model and points to a union type.", componentKey); @@ -2228,7 +2250,7 @@ internal static void AddDiscriminatorMethod(CodeClass newClass, string discrimin } if (baseClass is not null && (result.TypeDefinition is not CodeClass codeClass || codeClass.StartBlock.Inherits is null)) { - if (!baseClass.Equals(result.TypeDefinition))// don't log warning if the discriminator points to the base type itself as this is implicitly the default case. + if (!baseClass.Equals(result.TypeDefinition))// don't log warning if the discriminator points to the base type itself as this is implicitly the default case. logger.LogWarning("Discriminator {ComponentKey} is not inherited from {ClassName}.", componentKey, baseClass.Name); return null; } diff --git a/src/Kiota.Builder/LanguageInformation.cs b/src/Kiota.Builder/LanguageInformation.cs index c0b36309aa..d58dfa3b6a 100644 --- a/src/Kiota.Builder/LanguageInformation.cs +++ b/src/Kiota.Builder/LanguageInformation.cs @@ -15,9 +15,13 @@ public LanguageMaturityLevel MaturityLevel { get; set; } + public SupportExperience SupportExperience + { + get; set; + } #pragma warning disable CA2227 #pragma warning disable CA1002 - public List Dependencies { get; set; } = new(); + public List Dependencies { get; set; } = []; #pragma warning restore CA1002 #pragma warning restore CA2227 public string DependencyInstallCommand { get; set; } = string.Empty; @@ -32,11 +36,12 @@ public void SerializeAsV3(IOpenApiWriter writer) ArgumentNullException.ThrowIfNull(writer); writer.WriteStartObject(); writer.WriteProperty(nameof(MaturityLevel).ToFirstCharacterLowerCase(), MaturityLevel.ToString()); + writer.WriteProperty(nameof(SupportExperience).ToFirstCharacterLowerCase(), SupportExperience.ToString()); writer.WriteProperty(nameof(DependencyInstallCommand).ToFirstCharacterLowerCase(), DependencyInstallCommand); - writer.WriteOptionalCollection(nameof(Dependencies).ToFirstCharacterLowerCase(), Dependencies, (w, x) => x.SerializeAsV3(w)); + writer.WriteOptionalCollection(nameof(Dependencies).ToFirstCharacterLowerCase(), Dependencies, static (w, x) => x.SerializeAsV3(w)); writer.WriteProperty(nameof(ClientClassName).ToFirstCharacterLowerCase(), ClientClassName); writer.WriteProperty(nameof(ClientNamespaceName).ToFirstCharacterLowerCase(), ClientNamespaceName); - writer.WriteOptionalCollection(nameof(StructuredMimeTypes).ToFirstCharacterLowerCase(), StructuredMimeTypes, (w, x) => w.WriteValue(x)); + writer.WriteOptionalCollection(nameof(StructuredMimeTypes).ToFirstCharacterLowerCase(), StructuredMimeTypes, static (w, x) => w.WriteValue(x)); writer.WriteEndObject(); } public static LanguageInformation Parse(IOpenApiAny source) @@ -66,6 +71,14 @@ public static LanguageInformation Parse(IOpenApiAny source) foreach (var entry in structuredMimeTypesValue.OfType()) extension.StructuredMimeTypes.Add(entry.Value); } + if (rawObject.TryGetValue(nameof(MaturityLevel).ToFirstCharacterLowerCase(), out var maturityLevel) && maturityLevel is OpenApiString maturityLevelValue && Enum.TryParse(maturityLevelValue.Value, true, out var parsedMaturityLevelValue)) + { + extension.MaturityLevel = parsedMaturityLevelValue; + } + if (rawObject.TryGetValue(nameof(SupportExperience).ToFirstCharacterLowerCase(), out var supportExperience) && supportExperience is OpenApiString supportExperienceValue && Enum.TryParse(supportExperienceValue.Value, true, out var parsedSupportExperienceValue)) + { + extension.SupportExperience = parsedSupportExperienceValue; + } return extension; } } @@ -116,7 +129,14 @@ public enum LanguageMaturityLevel { Experimental, Preview, - Stable + Stable, + Abandoned +} + +public enum SupportExperience +{ + Microsoft, + Community } public enum DependencyType diff --git a/src/Kiota.Builder/Logging/FileLogLogger.cs b/src/Kiota.Builder/Logging/FileLogLogger.cs index dba4b6cf43..82a2cdb0c0 100644 --- a/src/Kiota.Builder/Logging/FileLogLogger.cs +++ b/src/Kiota.Builder/Logging/FileLogLogger.cs @@ -71,9 +71,6 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except } } -public class FileLogLogger : FileLogLogger, ILogger +public class FileLogLogger(string logFileDirectoryAbsolutePath, LogLevel logLevel) : FileLogLogger(logFileDirectoryAbsolutePath, logLevel, typeof(T).FullName ?? string.Empty), ILogger { - public FileLogLogger(string logFileDirectoryAbsolutePath, LogLevel logLevel) : base(logFileDirectoryAbsolutePath, logLevel, typeof(T).FullName ?? string.Empty) - { - } } diff --git a/src/Kiota.Builder/Logging/FileLogLoggerProvider.cs b/src/Kiota.Builder/Logging/FileLogLoggerProvider.cs index 2f0bb466ae..3ce3c650ca 100644 --- a/src/Kiota.Builder/Logging/FileLogLoggerProvider.cs +++ b/src/Kiota.Builder/Logging/FileLogLoggerProvider.cs @@ -4,16 +4,11 @@ namespace Kiota.Builder.Logging; -public sealed class FileLogLoggerProvider : ILoggerProvider +public sealed class FileLogLoggerProvider(string logFileDirectoryAbsolutePath, LogLevel logLevel) : ILoggerProvider { - private readonly LogLevel _logLevel; - private readonly string _logFileDirectoryAbsolutePath; - public FileLogLoggerProvider(string logFileDirectoryAbsolutePath, LogLevel logLevel) - { - _logLevel = logLevel; - _logFileDirectoryAbsolutePath = logFileDirectoryAbsolutePath; - } - private readonly List _loggers = new(); + private readonly LogLevel _logLevel = logLevel; + private readonly string _logFileDirectoryAbsolutePath = logFileDirectoryAbsolutePath; + private readonly List _loggers = []; public ILogger CreateLogger(string categoryName) { var instance = new FileLogLogger(_logFileDirectoryAbsolutePath, _logLevel, categoryName); diff --git a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs index ef638601fa..1406aa91c7 100644 --- a/src/Kiota.Builder/Plugins/PluginsGenerationService.cs +++ b/src/Kiota.Builder/Plugins/PluginsGenerationService.cs @@ -9,7 +9,9 @@ using Kiota.Builder.Configuration; using Kiota.Builder.Extensions; using Kiota.Builder.OpenApiExtensions; +using Microsoft.Extensions.Logging; using Microsoft.OpenApi.ApiManifest; +using Microsoft.OpenApi.Interfaces; using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Services; using Microsoft.OpenApi.Writers; @@ -23,9 +25,10 @@ public partial class PluginsGenerationService private readonly OpenApiUrlTreeNode TreeNode; private readonly GenerationConfiguration Configuration; private readonly string WorkingDirectory; + private readonly ILogger Logger; public PluginsGenerationService(OpenApiDocument document, OpenApiUrlTreeNode openApiUrlTreeNode, - GenerationConfiguration configuration, string workingDirectory) + GenerationConfiguration configuration, string workingDirectory, ILogger logger) { ArgumentNullException.ThrowIfNull(document); ArgumentNullException.ThrowIfNull(openApiUrlTreeNode); @@ -35,6 +38,7 @@ public PluginsGenerationService(OpenApiDocument document, OpenApiUrlTreeNode ope TreeNode = openApiUrlTreeNode; Configuration = configuration; WorkingDirectory = workingDirectory; + Logger = logger; } private static readonly OpenAPIRuntimeComparer _openAPIRuntimeComparer = new(); @@ -57,7 +61,10 @@ public async Task GenerateManifestAsync(CancellationToken cancellationToken = de #pragma warning restore CA2007 // Consider calling ConfigureAwait on the awaited task var descriptionWriter = new OpenApiYamlWriter(fileWriter); var trimmedPluginDocument = GetDocumentWithTrimmedComponentsAndResponses(OAIDocument); - trimmedPluginDocument = InlineRequestBodyAllOf(trimmedPluginDocument); + PrepareDescriptionForCopilot(trimmedPluginDocument); + // trimming a second time to remove any components that are no longer used after the inlining + trimmedPluginDocument = GetDocumentWithTrimmedComponentsAndResponses(trimmedPluginDocument); + trimmedPluginDocument.Info.Title = trimmedPluginDocument.Info.Title[..^9]; // removing the second ` - Subset` suffix from the title trimmedPluginDocument.SerializeAsV3(descriptionWriter); descriptionWriter.Flush(); @@ -102,126 +109,193 @@ public async Task GenerateManifestAsync(CancellationToken cancellationToken = de } } - private static OpenApiDocument InlineRequestBodyAllOf(OpenApiDocument openApiDocument) + private sealed class MappingCleanupVisitor(OpenApiDocument openApiDocument) : OpenApiVisitorBase { - if (openApiDocument.Paths is null) return openApiDocument; - var contentItems = openApiDocument.Paths.Values.Where(static x => x?.Operations is not null) - .SelectMany(static x => x.Operations.Values.Where(static x => x?.RequestBody?.Content is not null) - .SelectMany(static x => x.RequestBody.Content.Values)); - foreach (var contentItem in contentItems) + private readonly OpenApiDocument _document = openApiDocument; + + public override void Visit(OpenApiSchema schema) { - var schema = contentItem.Schema; - // Merge all schemas in allOf `schema.MergeAllOfSchemaEntries()` doesn't seem to do the right thing. - schema = MergeAllOfInSchema(schema); - schema = SelectFirstAnyOfOrOneOf(schema); - contentItem.Schema = schema; + if (schema.Discriminator?.Mapping is null) + return; + var keysToRemove = schema.Discriminator.Mapping.Where(x => !_document.Components.Schemas.ContainsKey(x.Value.Split('/', StringSplitOptions.RemoveEmptyEntries)[^1])).Select(static x => x.Key).ToArray(); + foreach (var key in keysToRemove) + schema.Discriminator.Mapping.Remove(key); + base.Visit(schema); } + } - return openApiDocument; + private sealed class AllOfPropertiesRetrievalVisitor : OpenApiVisitorBase + { + public override void Visit(OpenApiSchema schema) + { + if (schema.AllOf is not { Count: > 0 }) + return; + var allPropertiesToAdd = GetAllProperties(schema).ToArray(); + foreach (var allOfEntry in schema.AllOf) + SelectFirstAnyOneOfVisitor.CopyRelevantInformation(allOfEntry, schema, false, false, false); + foreach (var (key, value) in allPropertiesToAdd) + schema.Properties.TryAdd(key, value); + schema.AllOf.Clear(); + base.Visit(schema); + } + + private static IEnumerable> GetAllProperties(OpenApiSchema schema) + { + return schema.AllOf is not null ? + schema.AllOf.SelectMany(static x => GetAllProperties(x)).Union(schema.Properties) : + schema.Properties; + } + } - static OpenApiSchema? SelectFirstAnyOfOrOneOf(OpenApiSchema? schema) + private sealed class SelectFirstAnyOneOfVisitor : OpenApiVisitorBase + { + public override void Visit(OpenApiSchema schema) { - if (schema?.AnyOf is not { Count: > 0 } && schema?.OneOf is not { Count: > 0 }) return schema; - OpenApiSchema newSchema; if (schema.AnyOf is { Count: > 0 }) { - newSchema = schema.AnyOf[0]; + CopyRelevantInformation(schema.AnyOf[0], schema); + schema.AnyOf.Clear(); } - else if (schema.OneOf is { Count: > 0 }) + if (schema.OneOf is { Count: > 0 }) { - newSchema = schema.OneOf[0]; + CopyRelevantInformation(schema.OneOf[0], schema); + schema.OneOf.Clear(); } - else - { - newSchema = schema; - } - return newSchema; + base.Visit(schema); } - static OpenApiSchema? MergeAllOfInSchema(OpenApiSchema? schema) + internal static void CopyRelevantInformation(OpenApiSchema source, OpenApiSchema target, bool includeProperties = true, bool includeReference = true, bool includeDiscriminator = true) { - if (schema?.AllOf is not { Count: > 0 }) return schema; - var newSchema = new OpenApiSchema(); - foreach (var apiSchema in schema.AllOf) - { - if (apiSchema.Title is not null) newSchema.Title = apiSchema.Title; - if (!string.IsNullOrEmpty(apiSchema.Type)) - { - if (!string.IsNullOrEmpty(newSchema.Type) && newSchema.Type != apiSchema.Type) - { - throw new InvalidOperationException( - $"The schemas in allOf cannot have different types: '{newSchema.Type}' and '{apiSchema.Type}'."); - } - newSchema.Type = apiSchema.Type; - } - if (apiSchema.Format is not null) newSchema.Format = apiSchema.Format; - if (!string.IsNullOrEmpty(apiSchema.Description)) newSchema.Description = apiSchema.Description; - if (apiSchema.Maximum is not null) newSchema.Maximum = apiSchema.Maximum; - if (apiSchema.ExclusiveMaximum is not null) newSchema.ExclusiveMaximum = apiSchema.ExclusiveMaximum; - if (apiSchema.Minimum is not null) newSchema.Minimum = apiSchema.Minimum; - if (apiSchema.ExclusiveMinimum is not null) newSchema.ExclusiveMinimum = apiSchema.ExclusiveMinimum; - if (apiSchema.MaxLength is not null) newSchema.MaxLength = apiSchema.MaxLength; - if (apiSchema.MinLength is not null) newSchema.MinLength = apiSchema.MinLength; - if (!string.IsNullOrEmpty(apiSchema.Pattern)) newSchema.Pattern = apiSchema.Pattern; - if (apiSchema.MultipleOf is not null) newSchema.MultipleOf = apiSchema.MultipleOf; - if (apiSchema.Default is not null) newSchema.Default = apiSchema.Default; - if (apiSchema.ReadOnly) newSchema.ReadOnly = apiSchema.ReadOnly; - if (apiSchema.WriteOnly) newSchema.WriteOnly = apiSchema.WriteOnly; - if (apiSchema.Not is not null) newSchema.Not = apiSchema.Not; - if (apiSchema.Required is { Count: > 0 }) - { - foreach (var r in apiSchema.Required.Where(static r => !string.IsNullOrEmpty(r))) - { - newSchema.Required.Add(r); - } - } - if (apiSchema.Items is not null) newSchema.Items = apiSchema.Items; - if (apiSchema.MaxItems is not null) newSchema.MaxItems = apiSchema.MaxItems; - if (apiSchema.MinItems is not null) newSchema.MinItems = apiSchema.MinItems; - if (apiSchema.UniqueItems is not null) newSchema.UniqueItems = apiSchema.UniqueItems; - if (apiSchema.Properties is not null) - { - foreach (var property in apiSchema.Properties) - { - newSchema.Properties.TryAdd(property.Key, property.Value); - } - } - if (apiSchema.MaxProperties is not null) newSchema.MaxProperties = apiSchema.MaxProperties; - if (apiSchema.MinProperties is not null) newSchema.MinProperties = apiSchema.MinProperties; - if (apiSchema.AdditionalPropertiesAllowed) newSchema.AdditionalPropertiesAllowed = true; - if (apiSchema.AdditionalProperties is not null) newSchema.AdditionalProperties = apiSchema.AdditionalProperties; - if (apiSchema.Discriminator is not null) newSchema.Discriminator = apiSchema.Discriminator; - if (apiSchema.Example is not null) newSchema.Example = apiSchema.Example; - if (apiSchema.Enum is not null) - { - foreach (var enumValue in apiSchema.Enum) - { - newSchema.Enum.Add(enumValue); - } - } - if (apiSchema.Nullable) newSchema.Nullable = apiSchema.Nullable; - if (apiSchema.ExternalDocs is not null) newSchema.ExternalDocs = apiSchema.ExternalDocs; - if (apiSchema.Deprecated) newSchema.Deprecated = apiSchema.Deprecated; - if (apiSchema.Xml is not null) newSchema.Xml = apiSchema.Xml; - if (apiSchema.Extensions is not null) - { - foreach (var extension in apiSchema.Extensions) - { - newSchema.Extensions.Add(extension.Key, extension.Value); - } - } - if (apiSchema.Reference is not null) newSchema.Reference = apiSchema.Reference; - if (apiSchema.Annotations is not null) - { - foreach (var annotation in apiSchema.Annotations) - { - newSchema.Annotations.Add(annotation.Key, annotation.Value); - } - } - } - return newSchema; + if (!string.IsNullOrEmpty(source.Type)) + target.Type = source.Type; + if (!string.IsNullOrEmpty(source.Format)) + target.Format = source.Format; + if (source.Items is not null) + target.Items = source.Items; + if (source.Properties is not null && includeProperties) + target.Properties = new Dictionary(source.Properties); + if (source.Required is not null) + target.Required = new HashSet(source.Required); + if (source.AdditionalProperties is not null) + target.AdditionalProperties = source.AdditionalProperties; + if (source.Enum is not null) + target.Enum = [.. source.Enum]; + if (source.ExclusiveMaximum is not null) + target.ExclusiveMaximum = source.ExclusiveMaximum; + if (source.ExclusiveMinimum is not null) + target.ExclusiveMinimum = source.ExclusiveMinimum; + if (source.Maximum is not null) + target.Maximum = source.Maximum; + if (source.Minimum is not null) + target.Minimum = source.Minimum; + if (source.MaxItems is not null) + target.MaxItems = source.MaxItems; + if (source.MinItems is not null) + target.MinItems = source.MinItems; + if (source.MaxLength is not null) + target.MaxLength = source.MaxLength; + if (source.MinLength is not null) + target.MinLength = source.MinLength; + if (source.Pattern is not null) + target.Pattern = source.Pattern; + if (source.MaxProperties is not null) + target.MaxProperties = source.MaxProperties; + if (source.MinProperties is not null) + target.MinProperties = source.MinProperties; + if (source.UniqueItems is not null) + target.UniqueItems = source.UniqueItems; + if (source.Nullable) + target.Nullable = true; + if (source.ReadOnly) + target.ReadOnly = true; + if (source.WriteOnly) + target.WriteOnly = true; + if (source.Deprecated) + target.Deprecated = true; + if (source.Xml is not null) + target.Xml = source.Xml; + if (source.ExternalDocs is not null) + target.ExternalDocs = source.ExternalDocs; + if (source.Example is not null) + target.Example = source.Example; + if (source.Extensions is not null) + target.Extensions = new Dictionary(source.Extensions); + if (source.Discriminator is not null && includeDiscriminator) + target.Discriminator = source.Discriminator; + if (!string.IsNullOrEmpty(source.Description)) + target.Description = source.Description; + if (!string.IsNullOrEmpty(source.Title)) + target.Title = source.Title; + if (source.Default is not null) + target.Default = source.Default; + if (source.Reference is not null && includeReference) + target.Reference = source.Reference; + } + } + + private sealed class ErrorResponsesCleanupVisitor : OpenApiVisitorBase + { + public override void Visit(OpenApiOperation operation) + { + if (operation.Responses is null) + return; + var errorResponses = operation.Responses.Where(static x => x.Key.StartsWith('4') || x.Key.StartsWith('5')).ToArray(); + foreach (var (key, value) in errorResponses) + operation.Responses.Remove(key); + base.Visit(operation); } } + private sealed class ExternalDocumentationCleanupVisitor : OpenApiVisitorBase + { + public override void Visit(OpenApiDocument doc) + { + if (doc.ExternalDocs is not null) + doc.ExternalDocs = null; + base.Visit(doc); + } + public override void Visit(OpenApiOperation operation) + { + if (operation.ExternalDocs is not null) + operation.ExternalDocs = null; + base.Visit(operation); + } + public override void Visit(OpenApiSchema schema) + { + if (schema.ExternalDocs is not null) + schema.ExternalDocs = null; + base.Visit(schema); + } + public override void Visit(OpenApiTag tag) + { + if (tag.ExternalDocs is not null) + tag.ExternalDocs = null; + base.Visit(tag); + } + } + + private static void PrepareDescriptionForCopilot(OpenApiDocument document) + { + var externalDocumentationCleanupVisitor = new ExternalDocumentationCleanupVisitor(); + var externalDocumentationCleanupWalker = new OpenApiWalker(externalDocumentationCleanupVisitor); + externalDocumentationCleanupWalker.Walk(document); + + var errorResponsesCleanupVisitor = new ErrorResponsesCleanupVisitor(); + var errorResponsesCleanupWalker = new OpenApiWalker(errorResponsesCleanupVisitor); + errorResponsesCleanupWalker.Walk(document); + + var selectFirstAnyOneOfVisitor = new SelectFirstAnyOneOfVisitor(); + var selectFirstAnyOneOfWalker = new OpenApiWalker(selectFirstAnyOneOfVisitor); + selectFirstAnyOneOfWalker.Walk(document); + + var allOfPropertiesRetrievalVisitor = new AllOfPropertiesRetrievalVisitor(); + var allOfPropertiesRetrievalWalker = new OpenApiWalker(allOfPropertiesRetrievalVisitor); + allOfPropertiesRetrievalWalker.Walk(document); + + var mappingCleanupVisitor = new MappingCleanupVisitor(document); + var mappingCleanupWalker = new OpenApiWalker(mappingCleanupVisitor); + mappingCleanupWalker.Walk(document); + } + [GeneratedRegex(@"[^a-zA-Z0-9_]+", RegexOptions.IgnoreCase | RegexOptions.Singleline, 2000)] private static partial Regex PluginNameCleanupRegex(); @@ -258,7 +332,7 @@ private OpenApiDocument GetDocumentWithTrimmedComponentsAndResponses(OpenApiDocu private PluginManifestDocument GetManifestDocument(string openApiDocumentPath) { - var (runtimes, functions, conversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(OAIDocument, Configuration.PluginAuthInformation, TreeNode, openApiDocumentPath); + var (runtimes, functions, conversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(OAIDocument, Configuration.PluginAuthInformation, TreeNode, openApiDocumentPath, Logger); var descriptionForHuman = OAIDocument.Info?.Description is string d && !string.IsNullOrEmpty(d) ? d : $"Description for {OAIDocument.Info?.Title}"; var manifestInfo = ExtractInfoFromDocument(OAIDocument.Info); var pluginManifestDocument = new PluginManifestDocument @@ -338,7 +412,7 @@ private sealed record OpenApiManifestInfo( string ContactEmail = DefaultContactEmail); private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimesFunctionsAndConversationStartersFromTree(OpenApiDocument document, PluginAuthConfiguration? authInformation, OpenApiUrlTreeNode currentNode, - string openApiDocumentPath) + string openApiDocumentPath, ILogger logger) { var runtimes = new List(); var functions = new List(); @@ -348,10 +422,21 @@ private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimes { foreach (var operation in pathItem.Operations.Values.Where(static x => !string.IsNullOrEmpty(x.OperationId))) { + var auth = configAuth; + try + { + auth = configAuth ?? GetAuth(operation.Security ?? document.SecurityRequirements); + } + catch (UnsupportedSecuritySchemeException e) + { + auth = new AnonymousAuth(); + logger.LogWarning("Authentication warning: {OperationId} - {Message}", operation.OperationId, e.Message); + } + runtimes.Add(new OpenApiRuntime { // Configuration overrides document information - Auth = configAuth ?? GetAuth(operation.Security ?? document.SecurityRequirements), + Auth = auth, Spec = new OpenApiRuntimeSpec { Url = openApiDocumentPath }, RunForFunctions = [operation.OperationId] }); @@ -376,7 +461,7 @@ private static (OpenApiRuntime[], Function[], ConversationStarter[]) GetRuntimes foreach (var node in currentNode.Children) { - var (childRuntimes, childFunctions, childConversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(document, authInformation, node.Value, openApiDocumentPath); + var (childRuntimes, childFunctions, childConversationStarters) = GetRuntimesFunctionsAndConversationStartersFromTree(document, authInformation, node.Value, openApiDocumentPath, logger); runtimes.AddRange(childRuntimes); functions.AddRange(childFunctions); conversationStarters.AddRange(childConversationStarters); @@ -391,7 +476,7 @@ private static Auth GetAuth(IList securityRequiremen const string tooManySchemesError = "Multiple security requirements are not supported. Operations can only list one security requirement."; if (securityRequirements.Count > 1 || securityRequirements.FirstOrDefault()?.Keys.Count > 1) { - throw new InvalidOperationException(tooManySchemesError); + throw new UnsupportedSecuritySchemeException(tooManySchemesError); } var security = securityRequirements.FirstOrDefault(); var opSecurity = security?.Keys.FirstOrDefault(); diff --git a/src/Kiota.Builder/Refiners/CliRefiner.cs b/src/Kiota.Builder/Refiners/CliRefiner.cs index d8fe315c45..8db2891caa 100644 --- a/src/Kiota.Builder/Refiners/CliRefiner.cs +++ b/src/Kiota.Builder/Refiners/CliRefiner.cs @@ -404,15 +404,17 @@ private static CodeType CreateCommandType(CodeTypeBase.CodeTypeCollectionKind co } private static readonly AdditionalUsingEvaluator[] additionalUsingEvaluators = - { - new(x => x is CodeClass { Kind: CodeClassKind.RequestBuilder }, + [ + new(static x => x is CodeClass { Kind: CodeClassKind.RequestBuilder }, "System.CommandLine", "Command", "RootCommand", "IConsole"), - new(x => x is CodeClass { Kind: CodeClassKind.RequestBuilder }, + new(static x => x is CodeClass { Kind: CodeClassKind.RequestBuilder }, "Microsoft.Kiota.Cli.Commons.IO", "IOutputFormatter", "IOutputFormatterFactory", "FormatterType", "PageLinkData", "IPagingService"), - new(x => x is CodeClass { Kind: CodeClassKind.RequestBuilder }, + new(static x => x is CodeClass { Kind: CodeClassKind.RequestBuilder }, "System.Text", "Encoding"), - new(x => x is CodeMethod { Kind: CodeMethodKind.RequestExecutor or CodeMethodKind.RequestGenerator }, - "Microsoft.Kiota.Cli.Commons.Extensions", "GetRequestAdapter") - }; + new(static x => x is CodeClass { Kind: CodeClassKind.RequestBuilder }, + "System.Linq", "Enumerable"), + new(static x => x is CodeMethod { Kind: CodeMethodKind.RequestExecutor or CodeMethodKind.RequestGenerator }, + "Microsoft.Kiota.Cli.Commons.Extensions", "GetRequestAdapter"), + ]; } diff --git a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs index 6cdaebe093..f8e037a16a 100644 --- a/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs +++ b/src/Kiota.Builder/Refiners/CommonLanguageRefiner.cs @@ -946,7 +946,7 @@ parent is CodeType parentType && foreach (var implement in currentParent .StartBlock .Implements - .Where(pi => !currentClass.Usings.Any(ci => ci.Name.Equals(pi.Name, StringComparison.OrdinalIgnoreCase)))) + .Where(pi => !currentClass.Usings.Any(ci => !ci.IsExternal && ci.Name.Equals(pi.Name, StringComparison.OrdinalIgnoreCase)))) { currentClass.StartBlock.AddImplements((CodeType)implement.Clone()); } @@ -1475,15 +1475,28 @@ protected static void RemoveRequestConfigurationClassesCommonProperties(CodeElem CrawlTree(currentElement, x => RemoveRequestConfigurationClassesCommonProperties(x, baseTypeUsing)); } - protected static void RemoveUntypedNodePropertyValues(CodeElement currentElement) + protected static void RemoveUntypedNodeTypeValues(CodeElement currentElement) { - if (currentElement is CodeProperty currentProperty - && currentElement.Parent is CodeClass parentClass - && currentProperty.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)) + switch (currentElement) { - parentClass.RemoveChildElement(currentProperty); + case CodeProperty currentProperty when currentElement.Parent is CodeClass parentClass && currentProperty.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase): + parentClass.RemoveChildElement(currentProperty); + break; + case CodeMethod currentMethod when currentMethod.IsOfKind(CodeMethodKind.RequestExecutor): + if (currentMethod.ReturnType.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)) + { + currentMethod.ReturnType = new CodeType { Name = "binary", IsExternal = true }; + } + if (currentMethod.Parameters.Where(x => x.Kind is CodeParameterKind.RequestBody && x.Type.Name.Equals(KiotaBuilder.UntypedNodeName, StringComparison.OrdinalIgnoreCase)).ToList() is { Count: > 0 } parameters) + { + foreach (var parameter in parameters) + { + parameter.Type = new CodeType { Name = "binary", IsExternal = true }; + } + } + break; } - CrawlTree(currentElement, RemoveUntypedNodePropertyValues); + CrawlTree(currentElement, RemoveUntypedNodeTypeValues); } protected static void RemoveRequestConfigurationClasses(CodeElement currentElement, CodeUsing? configurationParameterTypeUsing = null, CodeType? defaultValueForGenericTypeParam = null, bool keepRequestConfigurationClass = false, bool addDeprecation = false, CodeUsing? usingForDefaultGenericParameter = null) { diff --git a/src/Kiota.Builder/Refiners/GoRefiner.cs b/src/Kiota.Builder/Refiners/GoRefiner.cs index 2754d7e818..234cb625bf 100644 --- a/src/Kiota.Builder/Refiners/GoRefiner.cs +++ b/src/Kiota.Builder/Refiners/GoRefiner.cs @@ -148,7 +148,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken AddConstructorsForDefaultValues( generatedCode, true, - true, //forcing add as constructors are required for by factories + true, //forcing add as constructors are required for by factories new[] { CodeClassKind.RequestConfiguration }); cancellationToken.ThrowIfCancellationRequested(); MakeModelPropertiesNullable( @@ -744,6 +744,9 @@ private static void AddErrorAndStringsImportForEnums(CodeElement currentElement) "Duration", "TimeOnly", "DateOnly", + "TimeSpan", + "Time", + "ISODuration", "string", "UUID", "Guid" diff --git a/src/Kiota.Builder/Refiners/PhpRefiner.cs b/src/Kiota.Builder/Refiners/PhpRefiner.cs index 9317d8b17f..82e18c62f5 100644 --- a/src/Kiota.Builder/Refiners/PhpRefiner.cs +++ b/src/Kiota.Builder/Refiners/PhpRefiner.cs @@ -57,7 +57,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken AddParsableImplementsForModelClasses(generatedCode, "Parsable"); AddRequestConfigurationConstructors(generatedCode); AddDefaultImports(generatedCode, defaultUsingEvaluators); - RemoveUntypedNodePropertyValues(generatedCode); + RemoveUntypedNodeTypeValues(generatedCode); AddCollectionValidationUtilImportToModels(generatedCode); cancellationToken.ThrowIfCancellationRequested(); AddGetterAndSetterMethods(generatedCode, diff --git a/src/Kiota.Builder/Refiners/PythonRefiner.cs b/src/Kiota.Builder/Refiners/PythonRefiner.cs index 337b489947..dc9964867a 100644 --- a/src/Kiota.Builder/Refiners/PythonRefiner.cs +++ b/src/Kiota.Builder/Refiners/PythonRefiner.cs @@ -26,7 +26,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken ); CorrectCommonNames(generatedCode); RemoveMethodByKind(generatedCode, CodeMethodKind.RawUrlConstructor); - RemoveUntypedNodePropertyValues(generatedCode); + RemoveUntypedNodeTypeValues(generatedCode); DisableActionOf(generatedCode, CodeParameterKind.RequestConfiguration); MoveRequestBuilderPropertiesToBaseType(generatedCode, diff --git a/src/Kiota.Builder/Refiners/RubyRefiner.cs b/src/Kiota.Builder/Refiners/RubyRefiner.cs index bf8f314cc5..5bfa96034c 100644 --- a/src/Kiota.Builder/Refiners/RubyRefiner.cs +++ b/src/Kiota.Builder/Refiners/RubyRefiner.cs @@ -63,7 +63,7 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken cancellationToken.ThrowIfCancellationRequested(); AddParsableImplementsForModelClasses(generatedCode, "MicrosoftKiotaAbstractions::Parsable"); AddDefaultImports(generatedCode, defaultUsingEvaluators); - RemoveUntypedNodePropertyValues(generatedCode); + RemoveUntypedNodeTypeValues(generatedCode); CorrectCoreType(generatedCode, CorrectMethodType, CorrectPropertyType, CorrectImplements); cancellationToken.ThrowIfCancellationRequested(); ReplacePropertyNames(generatedCode, diff --git a/src/Kiota.Builder/Refiners/SwiftRefiner.cs b/src/Kiota.Builder/Refiners/SwiftRefiner.cs index 21d47fb003..589025c6fe 100644 --- a/src/Kiota.Builder/Refiners/SwiftRefiner.cs +++ b/src/Kiota.Builder/Refiners/SwiftRefiner.cs @@ -41,10 +41,10 @@ public override Task RefineAsync(CodeNamespace generatedCode, CancellationToken true, false, true); + RemoveUntypedNodeTypeValues(generatedCode); AddDefaultImports( generatedCode, defaultUsingEvaluators); - RemoveUntypedNodePropertyValues(generatedCode); cancellationToken.ThrowIfCancellationRequested(); CorrectCoreType( generatedCode, diff --git a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs index 4b634c7d08..ca06132982 100644 --- a/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs +++ b/src/Kiota.Builder/Refiners/TypeScriptRefiner.cs @@ -1493,22 +1493,26 @@ private static void AddDeserializerUsingToDiscriminatorFactory(CodeElement codeE foreach (var mappedType in parsableFactoryFunction.OriginalMethodParentClass.DiscriminatorInformation.DiscriminatorMappings) { - if (mappedType.Value is CodeType type && type.TypeDefinition is CodeClass mappedClass) + if (mappedType.Value is not + { TypeDefinition: CodeClass { Parent: CodeNamespace codeNamespace } mappedClass } + || codeNamespace.FindChildByName( + $"{ModelDeserializerPrefix}{mappedClass.Name.ToFirstCharacterUpperCase()}") is not + { } deserializer) { - var deserializer = GetSerializationFunctionsForNamespace(mappedClass).Item2; + continue; + } - if (deserializer.Parent is not null) + if (deserializer.Parent is not null) + { + parsableFactoryFunction.AddUsing(new CodeUsing { - parsableFactoryFunction.AddUsing(new CodeUsing + Name = deserializer.Parent.Name, + Declaration = new CodeType { - Name = deserializer.Parent.Name, - Declaration = new CodeType - { - Name = deserializer.Name, - TypeDefinition = deserializer - }, - }); - } + Name = deserializer.Name, + TypeDefinition = deserializer + }, + }); } } } diff --git a/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs b/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs index da96ec88a5..5372d7a114 100644 --- a/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CLI/CliCodeMethodWriter.cs @@ -641,7 +641,7 @@ protected virtual void WriteCommandHandlerBody(CodeMethod codeElement, CodeClass if (requestBodyParamType?.TypeDefinition is CodeClass) { writer.WriteLine($"using var stream = new MemoryStream(Encoding.UTF8.GetBytes({requestBodyParam.Name}));"); - writer.WriteLine($"var parseNode = ParseNodeFactoryRegistry.DefaultInstance.GetRootParseNode(\"{generatorMethod.RequestBodyContentType.SanitizeDoubleQuote()}\", stream);"); + writer.WriteLine($"var parseNode = await ParseNodeFactoryRegistry.DefaultInstance.GetRootParseNodeAsync(\"{generatorMethod.RequestBodyContentType.SanitizeDoubleQuote()}\", stream, {CancellationTokenParamName});"); var typeString = conventions.GetTypeString(requestBodyParamType, requestBodyParam, false); diff --git a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs index 2bee2503fb..b2a97e360b 100644 --- a/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/CSharp/CodeMethodWriter.cs @@ -140,7 +140,7 @@ private void WriteFactoryMethodBodyForUnionModel(CodeMethod codeElement, CodeCla } else if (propertyType.TypeDefinition is CodeClass && propertyType.IsCollection || propertyType.TypeDefinition is null || propertyType.TypeDefinition is CodeEnum) { - var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); + var typeName = conventions.GetTypeString(propertyType, codeElement, true, propertyType.TypeDefinition is CodeEnum && propertyType.CollectionKind is not CodeTypeBase.CodeTypeCollectionKind.None); var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value"; writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName})"); writer.WriteBlock(lines: $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};"); @@ -161,7 +161,7 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, { if (property.Type is CodeType propertyType) { - var typeName = conventions.GetTypeString(propertyType, codeElement, true, false); + var typeName = conventions.GetTypeString(propertyType, codeElement, true, propertyType.TypeDefinition is CodeEnum && propertyType.CollectionKind is not CodeTypeBase.CodeTypeCollectionKind.None); var valueVarName = $"{property.Name.ToFirstCharacterLowerCase()}Value"; writer.WriteLine($"{(includeElse ? "else " : string.Empty)}if({parseNodeParameter.Name.ToFirstCharacterLowerCase()}.{GetDeserializationMethodName(propertyType, codeElement)} is {typeName} {valueVarName})"); writer.WriteBlock(lines: $"{ResultVarName}.{property.Name.ToFirstCharacterUpperCase()} = {valueVarName};"); diff --git a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs index 542be4f681..ea026bd4c8 100644 --- a/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Go/CodeMethodWriter.cs @@ -195,13 +195,17 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, WriteCollectionCast(propertyTypeImportName, valueVarName, "cast", writer, isInterfaceType ? string.Empty : "*", !isInterfaceType); valueVarName = "cast"; } - else if (propertyType.TypeDefinition is CodeClass || propertyType.TypeDefinition is CodeInterface) + else if (propertyType.TypeDefinition is CodeClass || propertyType.TypeDefinition is CodeInterface || propertyType.TypeDefinition is CodeEnum) { + if (propertyType.TypeDefinition is CodeEnum) + { + propertyTypeImportName = conventions.GetTypeString(property.Type, parentClass, false, true); + } writer.StartBlock($"if {GetTypeAssertion(valueVarName, propertyTypeImportName, "cast", "ok")}; ok {{"); valueVarName = "cast"; } writer.WriteLine($"{ResultVarName}.{property.Setter!.Name.ToFirstCharacterUpperCase()}({valueVarName})"); - if (!propertyType.IsCollection && (propertyType.TypeDefinition is CodeClass || propertyType.TypeDefinition is CodeInterface)) + if (!propertyType.IsCollection && (propertyType.TypeDefinition is CodeClass || propertyType.TypeDefinition is CodeInterface || propertyType.TypeDefinition is CodeEnum)) writer.CloseBlock(); writer.DecreaseIndent(); } diff --git a/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs b/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs index b85e876273..cd6789a8fa 100644 --- a/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs +++ b/src/Kiota.Builder/Writers/Php/CodeEnumWriter.cs @@ -47,7 +47,7 @@ public override void WriteCodeElement(CodeEnum codeElement, LanguageWriter write writer.IncreaseIndent(); foreach (var enumProperty in enumProperties) { - writer.WriteLine($"public const {GetEnumValueName(enumProperty.Name)} = '{enumProperty.WireName}';"); + writer.WriteLine($"public const {GetEnumValueName(enumProperty.Name)} = \"{enumProperty.WireName}\";"); } } [GeneratedRegex(@"([A-Z]{1})", RegexOptions.Singleline, 500)] diff --git a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs index a8601c382a..c1b25d996f 100644 --- a/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Php/CodeMethodWriter.cs @@ -475,35 +475,42 @@ _ when conventions.PrimitiveTypes.Contains(lowerCaseProp) => $"write{lowerCasePr } private const string ParseNodeVarName = "$parseNode"; - private string GetDeserializationMethodName(CodeTypeBase propType, CodeMethod method) + private (string, string) GetDeserializationMethodName(CodeTypeBase propType, CodeMethod method) { var isCollection = propType.CollectionKind != CodeTypeBase.CodeTypeCollectionKind.None; var propertyType = conventions.GetTypeString(propType, method, false); - var parseNodeMethod = string.Empty; + var parseNodeMethod = (string.Empty, string.Empty); if (propType is CodeType currentType) { if (isCollection) parseNodeMethod = currentType.TypeDefinition switch { - CodeEnum enumType => $"getCollectionOfEnumValues({enumType.Name.ToFirstCharacterUpperCase()}::class)", - _ => $"getCollectionOfObjectValues([{conventions.TranslateType(propType)}::class, '{CreateDiscriminatorMethodName}'])" + CodeEnum enumType => (string.Empty, $"getCollectionOfEnumValues({enumType.Name.ToFirstCharacterUpperCase()}::class)"), + CodeClass => (string.Empty, $"getCollectionOfObjectValues([{conventions.TranslateType(propType)}::class, '{CreateDiscriminatorMethodName}'])"), + _ => (conventions.TranslateType(propType), $"getCollectionOfPrimitiveValues('{conventions.TranslateType(propType)}')") }; else if (currentType.TypeDefinition is CodeEnum) - parseNodeMethod = $"getEnumValue({propertyType.ToFirstCharacterUpperCase()}::class)"; + parseNodeMethod = (string.Empty, $"getEnumValue({propertyType.ToFirstCharacterUpperCase()}::class)"); } var lowerCaseType = propertyType.ToLowerInvariant(); - return string.IsNullOrEmpty(parseNodeMethod) ? lowerCaseType switch - { - "int" => "getIntegerValue()", - "bool" => "getBooleanValue()", - "number" => "getIntegerValue()", - "decimal" or "double" => "getFloatValue()", - "streaminterface" => "getBinaryContent()", - "byte" => "getByteValue()", - _ when conventions.PrimitiveTypes.Contains(lowerCaseType) => $"get{propertyType.ToFirstCharacterUpperCase()}Value()", - _ => $"getObjectValue([{propertyType.ToFirstCharacterUpperCase()}::class, '{CreateDiscriminatorMethodName}'])", - } : parseNodeMethod; + var res = parseNodeMethod; + if (string.IsNullOrEmpty(parseNodeMethod.Item2)) + res = (string.Empty, lowerCaseType switch + { + "int" => "getIntegerValue()", + "bool" => "getBooleanValue()", + "number" => "getIntegerValue()", + "decimal" or "double" => "getFloatValue()", + "streaminterface" => "getBinaryContent()", + "byte" => "getByteValue()", + _ when conventions.PrimitiveTypes.Contains(lowerCaseType) => + $"get{propertyType.ToFirstCharacterUpperCase()}Value()", + _ => + $"getObjectValue([{propertyType.ToFirstCharacterUpperCase()}::class, '{CreateDiscriminatorMethodName}'])", + }); + + return res; } private void WriteSetterBody(LanguageWriter writer, CodeMethod codeElement, CodeClass parentClass) @@ -672,7 +679,7 @@ private void WriteDeserializerPropertyCallback(CodeProperty property, CodeMethod writer.WriteLine("},"); return; } - writer.WriteLine($"'{property.WireName}' => fn(ParseNode $n) => $o->{property.Setter!.Name.ToFirstCharacterLowerCase()}($n->{GetDeserializationMethodName(property.Type, method)}),"); + writer.WriteLine($"'{property.WireName}' => fn(ParseNode $n) => $o->{property.Setter!.Name.ToFirstCharacterLowerCase()}($n->{GetDeserializationMethodName(property.Type, method).Item2}),"); } private static void WriteDeserializerBodyForIntersectionModel(CodeClass parentClass, LanguageWriter writer) @@ -903,7 +910,8 @@ private void WriteFactoryMethodBodyForIntersectionModel(CodeMethod codeElement, { if (property.Type is CodeType propertyType) { - var deserializationMethodName = $"{ParseNodeVarName}->{GetDeserializationMethodName(propertyType, codeElement)}"; + var methodName = GetDeserializationMethodName(propertyType, codeElement); + var deserializationMethodName = $"{ParseNodeVarName}->{methodName.Item2}"; writer.StartBlock($"{(includeElse ? "} else " : string.Empty)}if ({deserializationMethodName} !== null) {{"); writer.WriteLine($"{ResultVarName}->{property.Setter!.Name.ToFirstCharacterLowerCase()}({deserializationMethodName});"); writer.DecreaseIndent(); @@ -973,9 +981,16 @@ private void WriteFactoryMethodBodyForUnionModelForUnDiscriminatedTypes(CodeMeth .ToArray(); foreach (var property in otherProps) { - var serializationMethodName = $"{ParseNodeVarName}->{GetDeserializationMethodName(property.Type, currentElement)}"; + var methodName = GetDeserializationMethodName(property.Type, currentElement); + var serializationMethodName = $"{ParseNodeVarName}->{methodName.Item2}"; + const string finalValueName = "$finalValue"; writer.StartBlock($"{(includeElse ? "} else " : string.Empty)}if ({serializationMethodName} !== null) {{"); - writer.WriteLine($"{ResultVarName}->{property.Setter!.Name.ToFirstCharacterLowerCase()}({serializationMethodName});"); + if (!string.IsNullOrEmpty(methodName.Item1)) + { + writer.WriteLine($"/** @var array<{methodName.Item1}> {finalValueName} */"); + } + writer.WriteLine($"{finalValueName} = {serializationMethodName};"); + writer.WriteLine($"{ResultVarName}->{property.Setter!.Name.ToFirstCharacterLowerCase()}({finalValueName});"); writer.DecreaseIndent(); if (!includeElse) includeElse = true; diff --git a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs index 67cee78295..230fa1b527 100644 --- a/src/Kiota.Builder/Writers/Php/PhpConventionService.cs +++ b/src/Kiota.Builder/Writers/Php/PhpConventionService.cs @@ -135,7 +135,7 @@ private string GetCollectionDocString(CodeParameter codeParameter) return codeParameter.Optional ? $"{doc}|null" : doc; } - internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription.Replace("\\", "/", StringComparison.OrdinalIgnoreCase); + internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription.Replace("\\", "/", StringComparison.OrdinalIgnoreCase).Replace("*/", string.Empty, StringComparison.OrdinalIgnoreCase); public override bool WriteShortDescription(IDocumentedElement element, LanguageWriter writer, string prefix = "", string suffix = "") { ArgumentNullException.ThrowIfNull(writer); diff --git a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs index 3b391cdb8f..a017ad072d 100644 --- a/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs +++ b/src/Kiota.Builder/Writers/Python/CodeMethodWriter.cs @@ -384,10 +384,15 @@ private void WriteDirectAccessProperties(CodeClass parentClass, LanguageWriter w { var returnType = conventions.GetTypeString(propWithDefault.Type, propWithDefault, true, writer); var defaultValue = propWithDefault.DefaultValue; - if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum enumDefinition) + switch (propWithDefault.Type) { - _codeUsingWriter.WriteDeferredImport(parentClass, enumDefinition.Name, writer); - defaultValue = $"{enumDefinition.Name}({defaultValue})"; + case CodeType { TypeDefinition: CodeEnum enumDefinition }: + _codeUsingWriter.WriteDeferredImport(parentClass, enumDefinition.Name, writer); + defaultValue = $"{enumDefinition.Name}({defaultValue})"; + break; + case CodeType propType when propType.Name.Equals("boolean", StringComparison.OrdinalIgnoreCase): + defaultValue = defaultValue.TrimQuotes().ToFirstCharacterUpperCase();// python booleans start in uppercase + break; } conventions.WriteInLineDescription(propWithDefault, writer); if (parentClass.IsOfKind(CodeClassKind.Model)) @@ -412,10 +417,15 @@ private void WriteSetterAccessProperties(CodeClass parentClass, LanguageWriter w .ThenBy(static x => x.Name)) { var defaultValue = propWithDefault.DefaultValue; - if (propWithDefault.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum enumDefinition) + switch (propWithDefault.Type) { - _codeUsingWriter.WriteDeferredImport(parentClass, enumDefinition.Name, writer); - defaultValue = $"{enumDefinition.Name}({defaultValue})"; + case CodeType { TypeDefinition: CodeEnum enumDefinition }: + _codeUsingWriter.WriteDeferredImport(parentClass, enumDefinition.Name, writer); + defaultValue = $"{enumDefinition.Name}({defaultValue})"; + break; + case CodeType propType when propType.Name.Equals("boolean", StringComparison.OrdinalIgnoreCase): + defaultValue = defaultValue.TrimQuotes().ToFirstCharacterUpperCase();// python booleans start in uppercase + break; } var returnType = conventions.GetTypeString(propWithDefault.Type, propWithDefault, true, writer); conventions.WriteInLineDescription(propWithDefault, writer); @@ -583,7 +593,7 @@ private void WriteRequestExecutorBody(CodeMethod codeElement, RequestParams requ var isStream = conventions.StreamTypeName.Equals(returnType, StringComparison.OrdinalIgnoreCase); var returnTypeWithoutCollectionSymbol = GetReturnTypeWithoutCollectionSymbol(codeElement, returnType); var genericTypeForSendMethod = GetSendRequestMethodName(isVoid, isStream, codeElement.ReturnType.IsCollection, returnTypeWithoutCollectionSymbol, isEnum); - var newFactoryParameter = GetTypeFactory(isVoid, isStream, isEnum, returnTypeWithoutCollectionSymbol); + var newFactoryParameter = GetTypeFactory(isVoid, isStream, isEnum, returnTypeWithoutCollectionSymbol, codeElement.ReturnType.IsCollection); var errorMappingVarName = NoneKeyword; if (codeElement.ErrorMappings.Any()) { @@ -809,11 +819,11 @@ private string GetSerializationMethodName(CodeTypeBase propType) _ => "write_object_value", }; } - internal string GetTypeFactory(bool isVoid, bool isStream, bool isEnum, string returnType) + internal string GetTypeFactory(bool isVoid, bool isStream, bool isEnum, string returnType, bool isCollection) { if (isVoid) return string.Empty; if (isStream || isEnum) return $" \"{returnType}\","; - if (conventions.IsPrimitiveType(returnType)) return $" {returnType},"; + if (conventions.IsPrimitiveType(returnType)) return isCollection ? $" {returnType}," : $" \"{returnType}\","; return $" {returnType},"; } private string GetSendRequestMethodName(bool isVoid, bool isStream, bool isCollection, string returnType, diff --git a/src/Kiota.Builder/Writers/Python/PythonConventionService.cs b/src/Kiota.Builder/Writers/Python/PythonConventionService.cs index 0daa153fd5..52e4a46921 100644 --- a/src/Kiota.Builder/Writers/Python/PythonConventionService.cs +++ b/src/Kiota.Builder/Writers/Python/PythonConventionService.cs @@ -95,7 +95,7 @@ public override string GetTypeString(CodeTypeBase code, CodeElement targetElemen throw new InvalidOperationException($"type of type {code.GetType()} is unknown"); } #pragma warning restore CA1822 // Method should be static - internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription.Replace("\\", "/", StringComparison.OrdinalIgnoreCase); + internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription.Replace("\\", "/", StringComparison.OrdinalIgnoreCase).Replace("\"\"\"", "\\\"\\\"\\\"", StringComparison.OrdinalIgnoreCase); public override string TranslateType(CodeType type) { ArgumentNullException.ThrowIfNull(type); @@ -130,7 +130,7 @@ public bool IsPrimitiveType(string typeName) { return typeName switch { - "int" or "float" or "str" or "bool" or "None" => true, + "int" or "float" or "str" or "bool" or "None" or "datetime.datetime" or "datetime.timedelta" or "datetime.date" or "datetime.time" => true, _ => false, }; } diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeConstantWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeConstantWriter.cs index b75590008a..f9f41d41a8 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeConstantWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeConstantWriter.cs @@ -102,7 +102,7 @@ private void WriteRequestsMetadataConstant(CodeConstant codeElement, LanguageWri var isStream = conventions.StreamTypeName.Equals(returnType, StringComparison.OrdinalIgnoreCase); var isEnum = executorMethod.ReturnType is CodeType codeType && codeType.TypeDefinition is CodeEnum; var returnTypeWithoutCollectionSymbol = GetReturnTypeWithoutCollectionSymbol(executorMethod, returnType); - var isPrimitive = IsPrimitiveType(returnTypeWithoutCollectionSymbol); + var isPrimitive = IsPrimitiveType(returnTypeWithoutCollectionSymbol) || IsKiotaPrimitive(returnTypeWithoutCollectionSymbol); var isPrimitiveAlias = GetPrimitiveAlias(returnTypeWithoutCollectionSymbol) is not null; writer.StartBlock($"{executorMethod.Name.ToFirstCharacterLowerCase()}: {{"); var urlTemplateValue = executorMethod.HasUrlTemplateOverride ? $"\"{executorMethod.UrlTemplateOverride}\"" : uriTemplateConstant.Name.ToFirstCharacterUpperCase(); @@ -169,7 +169,7 @@ private string GetTypeFactory(bool isVoid, bool isStream, CodeMethod codeElement { if (isVoid) return string.Empty; var typeName = conventions.TranslateType(codeElement.ReturnType); - if (isStream || IsPrimitiveType(typeName)) return $" \"{typeName}\""; + if (isStream || IsPrimitiveType(typeName) || IsKiotaPrimitive(typeName)) return $" \"{typeName}\""; if (GetPrimitiveAlias(typeName) is { } alias && !string.IsNullOrEmpty(alias)) return $" \"{alias}\""; return $" {GetFactoryMethodName(codeElement.ReturnType, codeElement, writer)}"; diff --git a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs index 1710944648..c21197ae14 100644 --- a/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs +++ b/src/Kiota.Builder/Writers/TypeScript/CodeFunctionWriter.cs @@ -117,7 +117,7 @@ private void WriteComposedTypeSerializer(CodeFunction codeElement, LanguageWrite private void WriteSerializationFunctionForCodeIntersectionType(CodeComposedTypeBase composedType, CodeParameter composedParam, CodeFunction method, LanguageWriter writer) { - foreach (var mappedType in composedType.Types.Where(x => !IsPrimitiveType(x, composedType))) + foreach (var mappedType in composedType.Types.Where(x => !IsPrimitiveType(x, composedType) && x.TypeDefinition != null)) { var functionName = GetSerializerFunctionName(method, mappedType); var variableName = composedParam.Name.ToFirstCharacterLowerCase(); @@ -611,9 +611,17 @@ private static string GetDefaultValueSuffix(CodeProperty otherProp) private static string GetDefaultValueLiteralForProperty(CodeProperty codeProperty) { if (string.IsNullOrEmpty(codeProperty.DefaultValue)) return string.Empty; - if (codeProperty.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum enumDefinition && enumDefinition.CodeEnumObject is not null) - return $"{enumDefinition.CodeEnumObject.Name.ToFirstCharacterUpperCase()}.{codeProperty.DefaultValue.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}"; - return codeProperty.DefaultValue; + if (codeProperty.Type is CodeType propertyType && propertyType.TypeDefinition is CodeEnum enumDefinition && + enumDefinition.CodeEnumObject is not null) + { + var codeEnumOption = enumDefinition.Options.First(x => + x.SymbolName.Equals(codeProperty.DefaultValue.Trim('"').CleanupSymbolName(), + StringComparison.OrdinalIgnoreCase)); + return $"{enumDefinition.CodeEnumObject.Name.ToFirstCharacterUpperCase()}.{codeEnumOption.Name.Trim('"').CleanupSymbolName().ToFirstCharacterUpperCase()}"; + } + + // only string primitive should keep quotes + return codeProperty.Type.Name.Equals("string", StringComparison.Ordinal) ? codeProperty.DefaultValue : codeProperty.DefaultValue.Trim('"'); } private void WriteDefensiveStatements(CodeMethod codeElement, LanguageWriter writer) { diff --git a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs index 90a6ac83e3..a963796ba6 100644 --- a/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs +++ b/src/Kiota.Builder/Writers/TypeScript/TypeScriptConventionService.cs @@ -99,7 +99,7 @@ public override string GetParameterSignature(CodeParameter parameter, CodeElemen // add a 'Parsable' type to the parameter if it is composed of non-Parsable types var parsableTypes = ( - composedType != null && !composedType.IsComposedOfObjects(IsPrimitiveType), + composedType != null && (!composedType.IsComposedOfObjects(IsPrimitiveType) || composedType.Types.Any(x => x.IsCollection)), parameter.Parent is CodeMethod method && (method.IsOfKind(CodeMethodKind.Deserializer, CodeMethodKind.Serializer)) ) switch { @@ -237,6 +237,18 @@ TYPE_LOWERCASE_BOOLEAN or }; } + // Types that are imported from kiota-abstractions and considered as primitive types + public static bool IsKiotaPrimitive(string typeName) + { + return typeName switch + { + TYPE_DATE_ONLY or + TYPE_TIME_ONLY or + TYPE_DURATION => true, + _ => false, + }; + } + public static string? GetPrimitiveAlias(string typeName) { return typeName switch @@ -252,7 +264,18 @@ TYPE_LOWERCASE_BOOLEAN or private static bool IsPrimitiveTypeOrPrimitiveCollection(CodeType codeType, CodeComposedTypeBase codeComposedTypeBase) => IsPrimitiveType(codeType, codeComposedTypeBase, false); - internal static string RemoveInvalidDescriptionCharacters(string originalDescription) => originalDescription?.Replace("\\", "/", StringComparison.OrdinalIgnoreCase) ?? string.Empty; + private static Dictionary InvalidCharactersReplacements = new(StringComparer.OrdinalIgnoreCase) { + { "\\", "/"}, + { "/*", "//*"} + }; + + internal static string RemoveInvalidDescriptionCharacters(string originalDescription) + { + if (string.IsNullOrEmpty(originalDescription)) return string.Empty; + originalDescription = InvalidCharactersReplacements + .Aggregate(originalDescription, (current, replacement) => current.Replace(replacement.Key, replacement.Value, StringComparison.OrdinalIgnoreCase)); + return originalDescription; + } public override bool WriteShortDescription(IDocumentedElement element, LanguageWriter writer, string prefix = "", string suffix = "") { ArgumentNullException.ThrowIfNull(writer); diff --git a/src/kiota/Handlers/BaseKiotaCommandHandler.cs b/src/kiota/Handlers/BaseKiotaCommandHandler.cs index 700bf37711..a7b857b22a 100644 --- a/src/kiota/Handlers/BaseKiotaCommandHandler.cs +++ b/src/kiota/Handlers/BaseKiotaCommandHandler.cs @@ -132,7 +132,7 @@ protected async Task CheckForNewVersionAsync(ILogger logger, CancellationToken c DisplayWarning(result); } public abstract Task InvokeAsync(InvocationContext context); - private readonly List disposables = new(); + private readonly List disposables = []; protected (ILoggerFactory, ILogger) GetLoggerAndFactory(InvocationContext context, string logFileRootPath = "") { LogLevel logLevel = context.ParseResult.GetValueForOption(LogLevelOption); diff --git a/src/kiota/Handlers/KiotaInfoCommandHandler.cs b/src/kiota/Handlers/KiotaInfoCommandHandler.cs index 949b4f00b3..f60ab7f85e 100644 --- a/src/kiota/Handlers/KiotaInfoCommandHandler.cs +++ b/src/kiota/Handlers/KiotaInfoCommandHandler.cs @@ -113,6 +113,7 @@ private void ShowLanguagesTable() }; view.AddColumn(static x => x.Key, "Language"); view.AddColumn(static x => x.Value.MaturityLevel.ToString(), "Maturity Level"); + view.AddColumn(static x => x.Value.SupportExperience.ToString(), "Support Experience"); var console = new SystemConsole(); using var terminal = new SystemConsoleTerminal(console); var layout = new StackLayoutView { view }; @@ -125,6 +126,7 @@ private void ShowLanguageInformation(GenerationLanguage language, LanguagesInfor if (!json) { DisplayInfo($"The language {language} is currently in {languageInformation.MaturityLevel} maturity level.", + $"The support experience is provided by {languageInformation.SupportExperience}.", "After generating code for this language, you need to install the following packages:"); var orderedDependencies = languageInformation.Dependencies.OrderBy(static x => x.Name).Select(static x => x).ToList(); var filteredDependencies = (dependencyTypes.ToHashSet(), orderedDependencies.Any(static x => x.DependencyType is DependencyType.Bundle)) switch diff --git a/src/kiota/KiotaConfigurationExtensions.cs b/src/kiota/KiotaConfigurationExtensions.cs index c54572b1f6..33842b6978 100644 --- a/src/kiota/KiotaConfigurationExtensions.cs +++ b/src/kiota/KiotaConfigurationExtensions.cs @@ -37,6 +37,7 @@ public static void BindConfiguration(this KiotaConfiguration configObject, IConf ClientNamespaceName = section[nameof(LanguageInformation.ClientNamespaceName)] ?? string.Empty, DependencyInstallCommand = section[nameof(LanguageInformation.DependencyInstallCommand)] ?? string.Empty, MaturityLevel = Enum.TryParse(section[nameof(LanguageInformation.MaturityLevel)], true, out var ml) ? ml : LanguageMaturityLevel.Experimental, + SupportExperience = Enum.TryParse(section[nameof(LanguageInformation.SupportExperience)], true, out var se) ? se : SupportExperience.Community, }; section.GetSection(nameof(lngInfo.StructuredMimeTypes)).LoadHashSet(lngInfo.StructuredMimeTypes); var dependenciesSection = section.GetSection(nameof(lngInfo.Dependencies)); diff --git a/src/kiota/Rpc/IServer.cs b/src/kiota/Rpc/IServer.cs index de7a284c0a..32f1749c81 100644 --- a/src/kiota/Rpc/IServer.cs +++ b/src/kiota/Rpc/IServer.cs @@ -12,6 +12,8 @@ internal interface IServer Task GetManifestDetailsAsync(string manifestPath, string apiIdentifier, bool clearCache, CancellationToken cancellationToken); Task> GenerateAsync(string openAPIFilePath, string outputPath, GenerationLanguage language, string[] includePatterns, string[] excludePatterns, string clientClassName, string clientNamespaceName, bool usesBackingStore, bool cleanOutput, bool clearCache, bool excludeBackwardCompatible, string[] disabledValidationRules, string[] serializers, string[] deserializers, string[] structuredMimeTypes, bool includeAdditionalData, ConsumerOperation operation, CancellationToken cancellationToken); Task InfoForDescriptionAsync(string descriptionPath, bool clearCache, CancellationToken cancellationToken); - Task> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, ConsumerOperation operation, CancellationToken cancellationToken); + Task> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, PluginAuthType? pluginAuthType, string pluginAuthRefid, ConsumerOperation operation, CancellationToken cancellationToken); Task> MigrateFromLockFileAsync(string lockDirectoryPath, CancellationToken cancellationToken); + Task> RemoveClientAsync(string clientName, bool cleanOutput, CancellationToken cancellationToken); + Task> RemovePluginAsync(string pluginName, bool cleanOutput, CancellationToken cancellationToken); } diff --git a/src/kiota/Rpc/Server.cs b/src/kiota/Rpc/Server.cs index e866eab942..ca0af15d8d 100644 --- a/src/kiota/Rpc/Server.cs +++ b/src/kiota/Rpc/Server.cs @@ -184,7 +184,9 @@ public async Task> GenerateAsync(string openAPIFilePath, string o } return logger.LogEntries; } - public async Task> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, ConsumerOperation operation, CancellationToken cancellationToken) + public async Task> GeneratePluginAsync(string openAPIFilePath, string outputPath, PluginType[] pluginTypes, string[] includePatterns, + string[] excludePatterns, string clientClassName, bool cleanOutput, bool clearCache, string[] disabledValidationRules, + PluginAuthType? pluginAuthType, string? pluginAuthRefid, ConsumerOperation operation, CancellationToken cancellationToken) { var globalLogger = new ForwardedLogger(); var configuration = Configuration.Generation; @@ -206,6 +208,13 @@ public async Task> GeneratePluginAsync(string openAPIFilePath, st configuration.ExcludePatterns = excludePatterns.Select(static x => x.TrimQuotes()).ToHashSet(StringComparer.OrdinalIgnoreCase); configuration.OpenAPIFilePath = GetAbsolutePath(configuration.OpenAPIFilePath); configuration.OutputPath = NormalizeSlashesInPath(GetAbsolutePath(configuration.OutputPath)); + if (!string.IsNullOrEmpty(pluginAuthRefid) && pluginAuthType != null) + { + var pluginAuthConfig = new PluginAuthConfiguration(pluginAuthRefid); + pluginAuthConfig.AuthType = pluginAuthType.Value; + configuration.PluginAuthInformation = pluginAuthConfig; + } + try { using var fileLogger = new FileLogLogger(configuration.OutputPath, LogLevel.Warning); @@ -299,4 +308,29 @@ private static string NormalizeSlashesInPath(string path) return path.Replace('/', '\\'); return path.Replace('\\', '/'); } + + public Task> RemoveClientAsync(string clientName, bool cleanOutput, CancellationToken cancellationToken) + => RemoveClientOrPluginAsync(clientName, cleanOutput, "Client", (workspaceManagementService, clientName, cleanOutput, cancellationToken) => workspaceManagementService.RemoveClientAsync(clientName, cleanOutput, cancellationToken), cancellationToken); + + private static async Task> RemoveClientOrPluginAsync(string clientName, bool cleanOutput, string typeName, Func removal, CancellationToken cancellationToken) + { + ArgumentException.ThrowIfNullOrEmpty(clientName); + ArgumentException.ThrowIfNullOrEmpty(typeName); + ArgumentNullException.ThrowIfNull(removal); + var logger = new ForwardedLogger(); + try + { + var workspaceManagementService = new WorkspaceManagementService(logger, httpClient, IsConfigPreviewEnabled.Value); + await removal(workspaceManagementService, clientName, cleanOutput, cancellationToken).ConfigureAwait(false); + logger.LogInformation("{TypeName} {ClientName} removed successfully!", typeName, clientName); + } + catch (Exception ex) + { + logger.LogCritical(ex, "error removing the {TypeName}: {ExceptionMessage}", typeName.ToLowerInvariant(), ex.Message); + } + return logger.LogEntries; + } + + public async Task> RemovePluginAsync(string pluginName, bool cleanOutput, CancellationToken cancellationToken) + => await RemoveClientOrPluginAsync(pluginName, cleanOutput, "Plugin", (workspaceManagementService, pluginName, cleanOutput, cancellationToken) => workspaceManagementService.RemovePluginAsync(pluginName, cleanOutput, cancellationToken), cancellationToken); } diff --git a/src/kiota/appsettings.json b/src/kiota/appsettings.json index c785f4befb..a332489f69 100644 --- a/src/kiota/appsettings.json +++ b/src/kiota/appsettings.json @@ -24,6 +24,7 @@ "Languages": { "CSharp": { "MaturityLevel": "Stable", + "SupportExperience": "Microsoft", "Dependencies": [ { "Name": "Microsoft.Kiota.Abstractions", @@ -70,6 +71,7 @@ }, "Java": { "MaturityLevel": "Stable", + "SupportExperience": "Microsoft", "Dependencies": [ { "Name": "com.microsoft.kiota:microsoft-kiota-abstractions", @@ -123,6 +125,7 @@ }, "Go": { "MaturityLevel": "Stable", + "SupportExperience": "Microsoft", "Dependencies": [ { "Name": "github.com/microsoft/kiota-abstractions-go", @@ -169,6 +172,7 @@ }, "TypeScript": { "MaturityLevel": "Preview", + "SupportExperience": "Microsoft", "Dependencies": [ { "Name": "@microsoft/kiota-abstractions", @@ -215,6 +219,7 @@ }, "PHP": { "MaturityLevel": "Stable", + "SupportExperience": "Microsoft", "Dependencies": [ { "Name": "microsoft/kiota-abstractions", @@ -256,6 +261,7 @@ }, "Python": { "MaturityLevel": "Stable", + "SupportExperience": "Microsoft", "Dependencies": [ { "Name": "microsoft-kiota-abstractions", @@ -302,6 +308,7 @@ }, "Ruby": { "MaturityLevel": "Experimental", + "SupportExperience": "Community", "Dependencies": [ { "Name": "microsoft_kiota_abstractions", @@ -328,11 +335,13 @@ }, "Swift": { "MaturityLevel": "Experimental", + "SupportExperience": "Community", "Dependencies": [], "DependencyInstallCommand": "" }, "CLI": { "MaturityLevel": "Preview", + "SupportExperience": "Microsoft", "Dependencies": [ { "Name": "Microsoft.Kiota.Abstractions", @@ -420,4 +429,4 @@ "DependencyInstallCommand": "" } } -} +} \ No newline at end of file diff --git a/src/kiota/kiota.csproj b/src/kiota/kiota.csproj index 57ec4596cc..8a313c04d5 100644 --- a/src/kiota/kiota.csproj +++ b/src/kiota/kiota.csproj @@ -15,7 +15,7 @@ Microsoft.OpenApi.Kiota Microsoft.OpenApi.Kiota ./nupkg - 1.21.0 + 1.22.0 $(VersionSuffix) https://github.com/microsoft/kiota/releases @@ -39,20 +39,20 @@ - + - + - + - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj b/tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj index de043f8450..683a0b4ab9 100644 --- a/tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj +++ b/tests/Kiota.Builder.IntegrationTests/Kiota.Builder.IntegrationTests.csproj @@ -6,19 +6,19 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all - - - + + + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs b/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs index d0c7a81f9f..db1ff23416 100644 --- a/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs +++ b/tests/Kiota.Builder.Tests/Extensions/OpenApiSchemaExtensionsTests.cs @@ -567,6 +567,32 @@ public void IsIntersection() }; Assert.False(schema.IsInherited()); Assert.False(schema.IsIntersection()); + + schema = new OpenApiSchema + { + Title = "Trader Id", + AllOf = new List { + new () + { + Title = "UserId", + Description = "unique identifier", + Type = "string", + Pattern = "^[1-9][0-9]*$", + Example = new OpenApiString("1323232"), + Reference = new OpenApiReference + { + Id = "UserId" // This property makes the schema "meaningful" + } + } + }, + Reference = new OpenApiReference + { + Id = "TraderId" // This property makes the schema "meaningful" + } + }; + + Assert.False(schema.IsInherited()); + Assert.False(schema.IsIntersection()); } [Fact] public void MergesIntersection() @@ -647,6 +673,351 @@ public void MergesIntersectionRecursively() Assert.Equal("description", result.Description); Assert.True(result.Deprecated); } + + public class MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries + { + [Fact] + public void DoesMergeWithInheritance() + { + var schema = new OpenApiSchema() + { + Type = "object", + AnyOf = + [ + new() + { + Properties = new Dictionary() + { + ["one"] = new OpenApiSchema(), + }, + AllOf = + [ + new() + { + Reference = new() + { + Id = "BaseClass" + }, + }, + new() + { + Type = "object", + Properties = new Dictionary() + { + ["firstName"] = new OpenApiSchema(), + ["lastName"] = new OpenApiSchema() + } + }, + ] + }, + ], + }; + + var result = schema.MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries(); + Assert.True(schema.AnyOf[0].IsInherited()); + Assert.NotNull(result); + Assert.True(result.IsInherited()); + Assert.Contains("one", result.Properties.Keys); + Assert.Empty(result.AnyOf); + Assert.Equal(2, result.AllOf.Count); + } + [Fact] + public void DoesMergeWithIntersection() + { + var schema = new OpenApiSchema() + { + Type = "object", + AnyOf = + [ + new() + { + Properties = new Dictionary() + { + ["one"] = new OpenApiSchema(), + }, + AllOf = + [ + new() + { + Type = "object", + Properties = new Dictionary() + { + ["first"] = new OpenApiSchema(), + } + }, + new() + { + Type = "object", + Properties = new Dictionary() + { + ["second"] = new OpenApiSchema(), + } + }, + new() + { + Type = "object", + Properties = new Dictionary() + { + ["third"] = new OpenApiSchema(), + } + }, + ] + }, + ], + }; + + var result = schema.MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries(); + Assert.NotNull(result); + Assert.True(schema.AnyOf[0].IsIntersection()); + Assert.True(result.IsIntersection()); + Assert.Contains("one", result.Properties.Keys); + Assert.Empty(result.AnyOf); + Assert.Equal(3, result.AllOf.Count); + } + [Fact] + public void DoesNotMergeWithMoreThanOneInclusiveEntry() + { + var schema = new OpenApiSchema() + { + Type = "object", + AnyOf = + [ + new() + { + Properties = new Dictionary() + { + ["one"] = new OpenApiSchema(), + }, + AllOf = + [ + new() + { + Reference = new() + { + Id = "BaseClass" + }, + }, + new() + { + Type = "object", + Properties = new Dictionary() + { + ["firstName"] = new OpenApiSchema(), + ["lastName"] = new OpenApiSchema() + } + }, + ] + }, + new() { Type = "object" }, + ], + }; + + var result = schema.MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries(); + Assert.Null(result); + } + [Fact] + public void DoesNotMergeWithoutInheritanceOrIntersection() + { + var schema = new OpenApiSchema() + { + Type = "object", + AnyOf = + [ + new() + { + AllOf = + [ + new() + { + Type = "object", + Properties = new Dictionary() + { + ["firstName"] = new OpenApiSchema(), + ["lastName"] = new OpenApiSchema() + } + }, + ] + }, + ], + }; + + var result = schema.MergeSingleInclusiveUnionInheritanceOrIntersectionSchemaEntries(); + Assert.Null(result); + } + } + + public class MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries + { + [Fact] + public void DoesMergeWithInheritance() + { + var schema = new OpenApiSchema() + { + Type = "object", + OneOf = + [ + new() + { + Properties = new Dictionary() + { + ["one"] = new OpenApiSchema(), + }, + AllOf = + [ + new() + { + Reference = new() + { + Id = "BaseClass" + }, + }, + new() + { + Type = "object", + Properties = new Dictionary() + { + ["firstName"] = new OpenApiSchema(), + ["lastName"] = new OpenApiSchema() + } + }, + ] + }, + ], + }; + + var result = schema.MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries(); + Assert.True(schema.OneOf[0].IsInherited()); + Assert.NotNull(result); + Assert.True(result.IsInherited()); + Assert.Contains("one", result.Properties.Keys); + Assert.Empty(result.OneOf); + Assert.Equal(2, result.AllOf.Count); + } + [Fact] + public void DoesMergeWithIntersection() + { + var schema = new OpenApiSchema() + { + Type = "object", + OneOf = + [ + new() + { + Properties = new Dictionary() + { + ["one"] = new OpenApiSchema(), + }, + AllOf = + [ + new() + { + Type = "object", + Properties = new Dictionary() + { + ["first"] = new OpenApiSchema(), + } + }, + new() + { + Type = "object", + Properties = new Dictionary() + { + ["second"] = new OpenApiSchema(), + } + }, + new() + { + Type = "object", + Properties = new Dictionary() + { + ["third"] = new OpenApiSchema(), + } + }, + ] + }, + ], + }; + + var result = schema.MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries(); + Assert.NotNull(result); + Assert.True(schema.OneOf[0].IsIntersection()); + Assert.True(result.IsIntersection()); + Assert.Contains("one", result.Properties.Keys); + Assert.Empty(result.OneOf); + Assert.Equal(3, result.AllOf.Count); + } + [Fact] + public void DoesNotMergeWithMoreThanOneExclusiveEntry() + { + var schema = new OpenApiSchema() + { + Type = "object", + OneOf = + [ + new() + { + Properties = new Dictionary() + { + ["one"] = new OpenApiSchema(), + }, + AllOf = + [ + new() + { + Reference = new() + { + Id = "BaseClass" + }, + }, + new() + { + Type = "object", + Properties = new Dictionary() + { + ["firstName"] = new OpenApiSchema(), + ["lastName"] = new OpenApiSchema() + } + }, + ] + }, + new() { Type = "object" }, + ], + }; + + var result = schema.MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries(); + Assert.Null(result); + } + [Fact] + public void DoesNotMergeWithoutInheritanceOrIntersection() + { + var schema = new OpenApiSchema() + { + Type = "object", + OneOf = + [ + new() + { + AllOf = + [ + new() + { + Type = "object", + Properties = new Dictionary() + { + ["firstName"] = new OpenApiSchema(), + ["lastName"] = new OpenApiSchema() + } + }, + ] + }, + ], + }; + + var result = schema.MergeSingleExclusiveUnionInheritanceOrIntersectionSchemaEntries(); + Assert.Null(result); + } + } + [Fact] public void IsArrayFalseOnEmptyItems() { @@ -847,4 +1218,63 @@ public void IsOdataPrimitiveBackwardCompatible() }; Assert.True(schema.IsODataPrimitiveType()); } + [Fact] + public void ReturnsEmptyPropertyNameOnCircularReferences() + { + var entitySchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "microsoft.graph.entity" + }, + Properties = new Dictionary + { + ["id"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "microsoft.graph.entity" + } + } + } + }; + var userSchema = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "microsoft.graph.user" + }, + OneOf = + [ + entitySchema, + new OpenApiSchema + { + Type = "object", + Properties = new Dictionary + { + ["firstName"] = new OpenApiSchema + { + Reference = new OpenApiReference + { + Id = "microsoft.graph.entity" + } + } + } + } + ], + Discriminator = new OpenApiDiscriminator + { + Mapping = new Dictionary + { + ["microsoft.graph.entity"] = "entity", + ["microsoft.graph.user"] = "user" + } + } + }; + entitySchema.AllOf = + [ + userSchema + ]; + Assert.Empty(userSchema.GetDiscriminatorPropertyName()); + } } diff --git a/tests/Kiota.Builder.Tests/Kiota.Builder.Tests.csproj b/tests/Kiota.Builder.Tests/Kiota.Builder.Tests.csproj index 5f6c96fe13..a087921e6d 100644 --- a/tests/Kiota.Builder.Tests/Kiota.Builder.Tests.csproj +++ b/tests/Kiota.Builder.Tests/Kiota.Builder.Tests.csproj @@ -12,19 +12,19 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs index 606bbe5c62..7acf60fbb3 100644 --- a/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs +++ b/tests/Kiota.Builder.Tests/KiotaBuilderTests.cs @@ -8536,6 +8536,692 @@ public async Task InheritanceWithAllOfBaseClassNoAdditionalPropertiesAsync() Assert.Equal("baseDirectoryObject", link.StartBlock.Inherits.Name); } + [Fact] + public async Task ExclusiveUnionSingleEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + type: object + oneOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + ExampleWithSingleOneOfWithoutTypeObject: + oneOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + Component1: + type: object + required: + - objectType + properties: + objectType: + type: string + one: + type: string + + Component2: + type: object + required: + - objectType + properties: + objectType: + type: string + two: + type: string +"""); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + + // Verify that all three classes referenced by the discriminator inherit from baseDirectoryObject + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + var oneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(oneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + var twoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(twoProperty); + } + + [Fact] + public async Task ExclusiveUnionInheritanceEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + description: "ExampleWithSingleOneOfWithTypeObject" + type: object + oneOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + + ExampleWithSingleOneOfWithoutTypeObject: + description: "ExampleWithSingleOneOfWithoutTypeObject" + oneOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + ComponentCommon: + description: "ComponentCommon" + type: object + required: + - objectType + properties: + objectType: + type: string + common: + type: string + + Component1: + description: "Component1" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - type: object + description: "Component1Inner" + properties: + one: + type: string + properties: + anotherOne: + type: string + + Component2: + description: "Component2" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - type: object + description: "Component2Inner" + properties: + two: + type: string + properties: + anotherTwo: + type: string +"""); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + + // Verify that all three classes referenced by the discriminator inherit from baseDirectoryObject + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + // ExampleWithSingleOneOfWithTypeObject inherits from ComponentCommon + Assert.Equal("ComponentCommon", withObjectClass.BaseClass?.Name); + var withObjectClassOneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(withObjectClassOneProperty); + var withObjectClassAnotherOneProperty = withObjectClass.FindChildByName("anotherOne", false); + Assert.NotNull(withObjectClassAnotherOneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + // Component2 inherits from ComponentCommon + Assert.Equal("ComponentCommon", withoutObjectClass.BaseClass?.Name); + var withoutObjectClassTwoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(withoutObjectClassTwoProperty); + var withoutObjectClassClassAnotherTwoProperty = withoutObjectClass.FindChildByName("anotherTwo", false); + Assert.NotNull(withoutObjectClassClassAnotherTwoProperty); + } + + [Fact] + public async Task ExclusiveUnionIntersectionEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + description: "ExampleWithSingleOneOfWithTypeObject" + type: object + oneOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + + ExampleWithSingleOneOfWithoutTypeObject: + description: "ExampleWithSingleOneOfWithoutTypeObject" + oneOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + ComponentCommon: + description: "ComponentCommon" + type: object + required: + - objectType + properties: + objectType: + type: string + common: + type: string + + ComponentCommon2: + description: "ComponentCommon2" + type: object + properties: + common2: + type: string + + Component1: + description: "Component1" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - $ref: "#/components/schemas/ComponentCommon2" + - type: object + description: "Component1Self" + properties: + one: + type: string + properties: + anotherOne: + type: string + + Component2: + description: "Component2" + type: object + required: + - objectType + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - $ref: "#/components/schemas/ComponentCommon2" + - type: object + description: "Component2Self" + properties: + two: + type: string + properties: + anotherTwo: + type: string +"""); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + + // Verify both scenarios have all the properties available from all schemas + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + var withObjectClassOneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(withObjectClassOneProperty); + var withObjectClassCommonProperty = withObjectClass.FindChildByName("common", false); + Assert.NotNull(withObjectClassCommonProperty); + var withObjectClassCommon2Property = withObjectClass.FindChildByName("common2", false); + Assert.NotNull(withObjectClassCommon2Property); + var withObjectClassObjectTypeProperty = withObjectClass.FindChildByName("objectType", false); + Assert.NotNull(withObjectClassObjectTypeProperty); + var withObjectClassAnotherOneProperty = withObjectClass.FindChildByName("anotherOne", false); + Assert.NotNull(withObjectClassAnotherOneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + var withoutObjectClassTwoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(withoutObjectClassTwoProperty); + var withoutObjectClassCommonProperty = withoutObjectClass.FindChildByName("common", false); + Assert.NotNull(withoutObjectClassCommonProperty); + var withoutObjectClassCommon2Property = withoutObjectClass.FindChildByName("common2", false); + Assert.NotNull(withoutObjectClassCommon2Property); + var withoutObjectClassObjectTypeProperty = withoutObjectClass.FindChildByName("objectType", false); + Assert.NotNull(withoutObjectClassObjectTypeProperty); + var withoutObjectClassClassAnotherTwoProperty = withoutObjectClass.FindChildByName("anotherTwo", false); + Assert.NotNull(withoutObjectClassClassAnotherTwoProperty); + } + + [Fact] + public async Task InclusiveUnionSingleEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating anyOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + type: object + anyOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + ExampleWithSingleOneOfWithoutTypeObject: + anyOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + Component1: + type: object + required: + - objectType + properties: + objectType: + type: string + one: + type: string + + Component2: + type: object + required: + - objectType + properties: + objectType: + type: string + two: + type: string +"""); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + + // Verify that all three classes referenced by the discriminator inherit from baseDirectoryObject + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + var oneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(oneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withObjectClass); + var twoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(twoProperty); + } + + [Fact] + public async Task InclusiveUnionInheritanceEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + description: "ExampleWithSingleOneOfWithTypeObject" + type: object + anyOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + + ExampleWithSingleOneOfWithoutTypeObject: + description: "ExampleWithSingleOneOfWithoutTypeObject" + anyOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + ComponentCommon: + description: "ComponentCommon" + type: object + required: + - objectType + properties: + objectType: + type: string + common: + type: string + + Component1: + description: "Component1" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - type: object + description: "Component1Inner" + properties: + one: + type: string + properties: + anotherOne: + type: string + + Component2: + description: "Component2" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - type: object + description: "Component2Inner" + properties: + two: + type: string + properties: + anotherTwo: + type: string +"""); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + + // Verify that all three classes referenced by the discriminator inherit from baseDirectoryObject + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + // ExampleWithSingleOneOfWithTypeObject inherits from ComponentCommon + Assert.Equal("ComponentCommon", withObjectClass.BaseClass?.Name); + var withObjectClassOneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(withObjectClassOneProperty); + var withObjectClassAnotherOneProperty = withObjectClass.FindChildByName("anotherOne", false); + Assert.NotNull(withObjectClassAnotherOneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + // Component2 inherits from ComponentCommon + Assert.Equal("ComponentCommon", withoutObjectClass.BaseClass?.Name); + var withoutObjectClassTwoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(withoutObjectClassTwoProperty); + var withoutObjectClassClassAnotherTwoProperty = withoutObjectClass.FindChildByName("anotherTwo", false); + Assert.NotNull(withoutObjectClassClassAnotherTwoProperty); + } + + [Fact] + public async Task InclusiveUnionIntersectionEntriesMergingAsync() + { + var tempFilePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName()); + await using var fs = await GetDocumentStreamAsync( +""" +openapi: 3.0.0 +info: + title: "Generator not generating oneOf if the containing schema has type: object" + version: "1.0.0" +servers: + - url: https://mytodos.doesnotexist/ +paths: + /uses-components: + post: + description: Return something + responses: + "200": + description: OK + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsesComponents" +components: + schemas: + ExampleWithSingleOneOfWithTypeObject: + description: "ExampleWithSingleOneOfWithTypeObject" + type: object + anyOf: + - $ref: "#/components/schemas/Component1" + discriminator: + propertyName: objectType + + ExampleWithSingleOneOfWithoutTypeObject: + description: "ExampleWithSingleOneOfWithoutTypeObject" + anyOf: + - $ref: "#/components/schemas/Component2" + discriminator: + propertyName: objectType + + UsesComponents: + type: object + properties: + component_with_single_oneof_with_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithTypeObject" + component_with_single_oneof_without_type_object: + $ref: "#/components/schemas/ExampleWithSingleOneOfWithoutTypeObject" + + ComponentCommon: + description: "ComponentCommon" + type: object + required: + - objectType + properties: + objectType: + type: string + common: + type: string + + ComponentCommon2: + description: "ComponentCommon2" + type: object + properties: + common2: + type: string + + Component1: + description: "Component1" + type: object + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - $ref: "#/components/schemas/ComponentCommon2" + - type: object + description: "Component1Self" + properties: + one: + type: string + properties: + anotherOne: + type: string + + Component2: + description: "Component2" + type: object + required: + - objectType + allOf: + - $ref: "#/components/schemas/ComponentCommon" + - $ref: "#/components/schemas/ComponentCommon2" + - type: object + description: "Component2Self" + properties: + two: + type: string + properties: + anotherTwo: + type: string +"""); + var mockLogger = new Mock>(); + var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); + var document = await builder.CreateOpenApiDocumentAsync(fs); + var node = builder.CreateUriSpace(document); + var codeModel = builder.CreateSourceModel(node); + + // Verify both scenarios have all the properties available from all schemas + var withObjectClass = codeModel.FindChildByName("ExampleWithSingleOneOfWithTypeObject"); + Assert.NotNull(withObjectClass); + var withObjectClassOneProperty = withObjectClass.FindChildByName("one", false); + Assert.NotNull(withObjectClassOneProperty); + var withObjectClassCommonProperty = withObjectClass.FindChildByName("common", false); + Assert.NotNull(withObjectClassCommonProperty); + var withObjectClassCommon2Property = withObjectClass.FindChildByName("common2", false); + Assert.NotNull(withObjectClassCommon2Property); + var withObjectClassObjectTypeProperty = withObjectClass.FindChildByName("objectType", false); + Assert.NotNull(withObjectClassObjectTypeProperty); + var withObjectClassAnotherOneProperty = withObjectClass.FindChildByName("anotherOne", false); + Assert.NotNull(withObjectClassAnotherOneProperty); + + var withoutObjectClass = codeModel.FindChildByName("Component2"); + Assert.NotNull(withoutObjectClass); + var withoutObjectClassTwoProperty = withoutObjectClass.FindChildByName("two", false); + Assert.NotNull(withoutObjectClassTwoProperty); + var withoutObjectClassCommonProperty = withoutObjectClass.FindChildByName("common", false); + Assert.NotNull(withoutObjectClassCommonProperty); + var withoutObjectClassCommon2Property = withoutObjectClass.FindChildByName("common2", false); + Assert.NotNull(withoutObjectClassCommon2Property); + var withoutObjectClassObjectTypeProperty = withoutObjectClass.FindChildByName("objectType", false); + Assert.NotNull(withoutObjectClassObjectTypeProperty); + var withoutObjectClassClassAnotherTwoProperty = withoutObjectClass.FindChildByName("anotherTwo", false); + Assert.NotNull(withoutObjectClassClassAnotherTwoProperty); + } + [Fact] public async Task NestedIntersectionTypeAllOfAsync() { @@ -8846,14 +9532,14 @@ public async Task InheritanceWithAllOfWith3Parts1Schema2InlineAsync(bool reverse '#microsoft.graph.group': '#/components/schemas/microsoft.graph.group' microsoft.graph.group: allOf:" - + (reverseOrder ? "" : @" + + (reverseOrder ? "" : @" - '$ref': '#/components/schemas/microsoft.graph.directoryObject'") + @" - properties: groupprop1: type: 'string' - properties: groupprop2: - type: 'string'" + (!reverseOrder ? "" : @" + type: 'string'" + (!reverseOrder ? "" : @" - '$ref': '#/components/schemas/microsoft.graph.directoryObject'")); var mockLogger = new Mock>(); var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration { ClientClassName = "Graph", OpenAPIFilePath = tempFilePath }, _httpClient); diff --git a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiKiotaExtensionTests.cs b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiKiotaExtensionTests.cs index beb4c3fe4f..872f0ca6db 100644 --- a/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiKiotaExtensionTests.cs +++ b/tests/Kiota.Builder.Tests/OpenApiExtensions/OpenApiKiotaExtensionTests.cs @@ -27,6 +27,7 @@ public void Serializes() }, DependencyInstallCommand = "dotnet add package", MaturityLevel = LanguageMaturityLevel.Preview, + SupportExperience = SupportExperience.Microsoft, ClientClassName = "GraphServiceClient", ClientNamespaceName = "Microsoft.Graph", StructuredMimeTypes = new() { @@ -43,7 +44,7 @@ public void Serializes() value.Write(writer, OpenApiSpecVersion.OpenApi3_0); var result = sWriter.ToString(); - Assert.Equal("{\"languagesInformation\":{\"CSharp\":{\"maturityLevel\":\"Preview\",\"dependencyInstallCommand\":\"dotnet add package\",\"dependencies\":[{\"name\":\"Microsoft.Graph.Core\",\"version\":\"1.0.0\",\"type\":\"Bundle\"}],\"clientClassName\":\"GraphServiceClient\",\"clientNamespaceName\":\"Microsoft.Graph\",\"structuredMimeTypes\":[\"application/json\",\"application/xml\"]}}}", result); + Assert.Equal("{\"languagesInformation\":{\"CSharp\":{\"maturityLevel\":\"Preview\",\"supportExperience\":\"Microsoft\",\"dependencyInstallCommand\":\"dotnet add package\",\"dependencies\":[{\"name\":\"Microsoft.Graph.Core\",\"version\":\"1.0.0\",\"type\":\"Bundle\"}],\"clientClassName\":\"GraphServiceClient\",\"clientNamespaceName\":\"Microsoft.Graph\",\"structuredMimeTypes\":[\"application/json\",\"application/xml\"]}}}", result); } [Fact] public void Parses() @@ -61,6 +62,7 @@ public void Parses() }}, {"dependencyInstallCommand", new OpenApiString("dotnet add package") }, {"maturityLevel", new OpenApiString("Preview")}, + {"supportExperience", new OpenApiString("Microsoft")}, {"clientClassName", new OpenApiString("GraphServiceClient")}, {"clientNamespaceName", new OpenApiString("Microsoft.Graph")}, {"structuredMimeTypes", new OpenApiArray { @@ -75,7 +77,8 @@ public void Parses() Assert.NotNull(value); Assert.True(value.LanguagesInformation.TryGetValue("CSharp", out var CSEntry)); Assert.Equal("dotnet add package", CSEntry.DependencyInstallCommand); - Assert.Equal(LanguageMaturityLevel.Experimental, CSEntry.MaturityLevel); //expected as we're not parsing the value from the description + Assert.Equal(LanguageMaturityLevel.Preview, CSEntry.MaturityLevel); + Assert.Equal(SupportExperience.Microsoft, CSEntry.SupportExperience); Assert.Equal("GraphServiceClient", CSEntry.ClientClassName); Assert.Equal("Microsoft.Graph", CSEntry.ClientNamespaceName); Assert.Single(CSEntry.Dependencies); diff --git a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs index 3f74656037..6743f5c63a 100644 --- a/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs +++ b/tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs @@ -19,14 +19,14 @@ namespace Kiota.Builder.Tests.Plugins; public sealed class PluginsGenerationServiceTests : IDisposable { private readonly HttpClient _httpClient = new(); - + private readonly ILogger _logger = new Mock>().Object; [Fact] public void Defensive() { - Assert.Throws(() => new PluginsGenerationService(null, OpenApiUrlTreeNode.Create(), new(), "foo")); - Assert.Throws(() => new PluginsGenerationService(new(), null, new(), "foo")); - Assert.Throws(() => new PluginsGenerationService(new(), OpenApiUrlTreeNode.Create(), null, "foo")); - Assert.Throws(() => new PluginsGenerationService(new(), OpenApiUrlTreeNode.Create(), new(), string.Empty)); + Assert.Throws(() => new PluginsGenerationService(null, OpenApiUrlTreeNode.Create(), new(), "foo", _logger)); + Assert.Throws(() => new PluginsGenerationService(new(), null, new(), "foo", _logger)); + Assert.Throws(() => new PluginsGenerationService(new(), OpenApiUrlTreeNode.Create(), null, "foo", _logger)); + Assert.Throws(() => new PluginsGenerationService(new(), OpenApiUrlTreeNode.Create(), new(), string.Empty, _logger)); } public void Dispose() @@ -76,7 +76,7 @@ public async Task GeneratesManifestAsync(string inputPluginName, string expected var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml"; await File.WriteAllTextAsync(simpleDescriptionPath, simpleDescriptionContent); var mockLogger = new Mock>(); - var openAPIDocumentDS = new OpenApiDocumentDownloadService(_httpClient, mockLogger.Object); + var openAPIDocumentDS = new OpenApiDocumentDownloadService(_httpClient, _logger); var outputDirectory = Path.Combine(workingDirectory, "output"); var generationConfiguration = new GenerationConfiguration { @@ -91,7 +91,7 @@ public async Task GeneratesManifestAsync(string inputPluginName, string expected KiotaBuilder.CleanupOperationIdForPlugins(openApiDocument); var urlTreeNode = OpenApiUrlTreeNode.Create(openApiDocument, Constants.DefaultOpenApiLabel); - var pluginsGenerationService = new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory); + var pluginsGenerationService = new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory, _logger); await pluginsGenerationService.GenerateManifestAsync(); Assert.True(File.Exists(Path.Combine(outputDirectory, $"{expectedPluginName.ToLower()}-apiplugin.json"))); @@ -171,6 +171,9 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() /test: get: description: description for test path + externalDocs: + description: external docs for test path + url: http://localhost/test x-random-extension: true responses: '200': @@ -193,6 +196,10 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() responses: '200': description: + content: + application/json: + schema: + $ref: '#/components/schemas/microsoft.graph.message' '500': description: api error response components: @@ -204,14 +211,25 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() type: object properties: id: - type: string + anyOf: + - type: string + - type: integer '@odata.type': - type: string"; + type: string + microsoft.graph.message: + allOf: + - $ref: '#/components/schemas/microsoft.graph.entity' + - type: object + title: message + properties: + subject: + type: string + body: + type: string"; var workingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml"; await File.WriteAllTextAsync(simpleDescriptionPath, simpleDescriptionContent); - var mockLogger = new Mock>(); - var openAPIDocumentDS = new OpenApiDocumentDownloadService(_httpClient, mockLogger.Object); + var openAPIDocumentDS = new OpenApiDocumentDownloadService(_httpClient, _logger); var outputDirectory = Path.Combine(workingDirectory, "output"); var generationConfiguration = new GenerationConfiguration { @@ -226,7 +244,7 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() KiotaBuilder.CleanupOperationIdForPlugins(openApiDocument); var urlTreeNode = OpenApiUrlTreeNode.Create(openApiDocument, Constants.DefaultOpenApiLabel); - var pluginsGenerationService = new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory); + var pluginsGenerationService = new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory, _logger); await pluginsGenerationService.GenerateManifestAsync(); Assert.True(File.Exists(Path.Combine(outputDirectory, ManifestFileName))); @@ -251,13 +269,15 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() Assert.Equal(originalDocument.Paths["/test"].Operations[OperationType.Get].Description, resultingManifest.Document.Functions[0].Description);// pulls from description Assert.Equal(originalDocument.Paths["/test/{id}"].Operations[OperationType.Get].Summary, resultingManifest.Document.Functions[1].Description);// pulls from summary - Assert.Single(originalDocument.Components.Schemas);// one schema originally + Assert.NotNull(originalDocument.Paths["/test"].Operations[OperationType.Get].ExternalDocs); // existing external docs + Assert.Equal(2, originalDocument.Components.Schemas.Count);// one schema originally Assert.Single(originalDocument.Extensions); // single unsupported extension at root Assert.Equal(2, originalDocument.Paths.Count); // document has only two paths Assert.Equal(2, originalDocument.Paths["/test"].Operations[OperationType.Get].Responses.Count); // 2 responses originally Assert.Single(originalDocument.Paths["/test"].Operations[OperationType.Get].Extensions); // 1 UNsupported extension Assert.Equal(2, originalDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses.Count); // 2 responses originally Assert.Single(originalDocument.Paths["/test/{id}"].Operations[OperationType.Get].Extensions); // 1 supported extension + Assert.Equal(2, originalDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.AllOf[0].Properties["id"].AnyOf.Count); // anyOf we selected // Validate the output open api file var resultOpenApiFile = File.OpenRead(Path.Combine(outputDirectory, OpenApiFileName)); @@ -265,15 +285,20 @@ public async Task GeneratesManifestAndCleansUpInputDescriptionAsync() Assert.Empty(diagnostic.Errors); // Assertions / validations - Assert.Empty(resultDocument.Components.Schemas);// no schema is referenced. so ensure they are all removed + Assert.Single(resultDocument.Components.Schemas);// no schema is referenced. so ensure they are all removed Assert.Empty(resultDocument.Extensions); // no extension at root (unsupported extension is removed) Assert.Equal(2, resultDocument.Paths.Count); // document has only two paths - Assert.Equal(originalDocument.Paths["/test"].Operations[OperationType.Get].Responses.Count, resultDocument.Paths["/test"].Operations[OperationType.Get].Responses.Count); // Responses are still intact. + Assert.Equal(originalDocument.Paths["/test"].Operations[OperationType.Get].Responses.Count - 1, resultDocument.Paths["/test"].Operations[OperationType.Get].Responses.Count); // We removed the error response Assert.NotEmpty(resultDocument.Paths["/test"].Operations[OperationType.Get].Responses["200"].Description); // response description string is not empty + Assert.Null(resultDocument.Paths["/test"].Operations[OperationType.Get].ExternalDocs); // external docs are removed Assert.Empty(resultDocument.Paths["/test"].Operations[OperationType.Get].Extensions); // NO UNsupported extension - Assert.Equal(originalDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses.Count, resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses.Count); // Responses are still intact. + Assert.Equal(originalDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses.Count - 1, resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses.Count); // Responses are still intact. Assert.NotEmpty(resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Description);// response description string is not empty Assert.Single(resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Extensions); // 1 supported extension still present in operation + Assert.Empty(resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.AllOf); // allOf were merged + Assert.Empty(resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.Properties["id"].AnyOf); // anyOf we selected + Assert.Equal("string", resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses["200"].Content["application/json"].Schema.Properties["id"].Type); + Assert.DoesNotContain("500", resultDocument.Paths["/test/{id}"].Operations[OperationType.Get].Responses.Keys, StringComparer.OrdinalIgnoreCase); // We removed the error response } #region Security @@ -408,7 +433,33 @@ public static TheoryData(auth0); } + }, + // multiple security schemes in operation object + { + "{securitySchemes: {apiKey0: {type: apiKey, name: x-api-key0, in: header}, apiKey1: {type: apiKey, name: x-api-key1, in: header}}}", + string.Empty, "security: [apiKey0: [], apiKey1: []]", null, resultingManifest => + { + Assert.NotNull(resultingManifest.Document); + Assert.Empty(resultingManifest.Problems); + Assert.NotEmpty(resultingManifest.Document.Runtimes); + var auth0 = resultingManifest.Document.Runtimes[0].Auth; + Assert.IsType(auth0); + } + }, + // Unsupported security scheme (http basic) + { + "{securitySchemes: {httpBasic0: {type: http, scheme: basic}}}", + string.Empty, "security: [httpBasic0: []]", null, resultingManifest => + { + Assert.NotNull(resultingManifest.Document); + Assert.Empty(resultingManifest.Problems); + Assert.NotEmpty(resultingManifest.Document.Runtimes); + var auth0 = resultingManifest.Document.Runtimes[0].Auth; + Assert.IsType(auth0); + } } + + }; } @@ -437,7 +488,7 @@ public async Task GeneratesManifestWithAuthAsync(string securitySchemesComponent var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml"; await File.WriteAllTextAsync(simpleDescriptionPath, apiDescription); var mockLogger = new Mock>(); - var openApiDocumentDs = new OpenApiDocumentDownloadService(_httpClient, mockLogger.Object); + var openApiDocumentDs = new OpenApiDocumentDownloadService(_httpClient, _logger); var outputDirectory = Path.Combine(workingDirectory, "output"); var generationConfiguration = new GenerationConfiguration { @@ -457,7 +508,7 @@ public async Task GeneratesManifestWithAuthAsync(string securitySchemesComponent var urlTreeNode = OpenApiUrlTreeNode.Create(openApiDocument, Constants.DefaultOpenApiLabel); var pluginsGenerationService = - new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory); + new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory, _logger); await pluginsGenerationService.GenerateManifestAsync(); Assert.True(File.Exists(Path.Combine(outputDirectory, ManifestFileName))); @@ -480,98 +531,6 @@ public async Task GeneratesManifestWithAuthAsync(string securitySchemesComponent } } - public static TheoryData, Task>> - SecurityInformationFail() - { - return new TheoryData, Task>> - { - // multiple security schemes in operation object - { - "{securitySchemes: {apiKey0: {type: apiKey, name: x-api-key0, in: header}, apiKey1: {type: apiKey, name: x-api-key1, in: header}}}", - string.Empty, "security: [apiKey0: [], apiKey1: []]", null, async (action) => - { - await Assert.ThrowsAsync(async () => - { - await action(); - }); - } - }, - // Unsupported security scheme (http basic) - { - "{securitySchemes: {httpBasic0: {type: http, scheme: basic}}}", - string.Empty, "security: [httpBasic0: []]", null, async (action) => - { - await Assert.ThrowsAsync(async () => - { - await action(); - }); - } - }, - }; - } - - [Theory] - [MemberData(nameof(SecurityInformationFail))] - public async Task FailsToGeneratesManifestWithInvalidAuthAsync(string securitySchemesComponent, string rootSecurity, - string operationSecurity, PluginAuthConfiguration pluginAuthConfiguration, Func, Task> assertions) - { - var apiDescription = $""" - openapi: 3.0.0 - info: - title: test - version: "1.0" - paths: - /test: - get: - description: description for test path - responses: - '200': - description: test - {operationSecurity} - {rootSecurity} - components: {securitySchemesComponent} - """; - var workingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml"; - await File.WriteAllTextAsync(simpleDescriptionPath, apiDescription); - var mockLogger = new Mock>(); - var openApiDocumentDs = new OpenApiDocumentDownloadService(_httpClient, mockLogger.Object); - var outputDirectory = Path.Combine(workingDirectory, "output"); - var generationConfiguration = new GenerationConfiguration - { - OutputPath = outputDirectory, - OpenAPIFilePath = "openapiPath", - PluginTypes = [PluginType.APIPlugin], - ClientClassName = "client", - ApiRootUrl = "http://localhost/", //Kiota builder would set this for us - PluginAuthInformation = pluginAuthConfiguration, - }; - var (openApiDocumentStream, _) = - await openApiDocumentDs.LoadStreamAsync(simpleDescriptionPath, generationConfiguration, null, false); - var openApiDocument = - await openApiDocumentDs.GetDocumentFromStreamAsync(openApiDocumentStream, generationConfiguration); - Assert.NotNull(openApiDocument); - KiotaBuilder.CleanupOperationIdForPlugins(openApiDocument); - var urlTreeNode = OpenApiUrlTreeNode.Create(openApiDocument, Constants.DefaultOpenApiLabel); - - var pluginsGenerationService = - new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory); - - await assertions(async () => - { - await pluginsGenerationService.GenerateManifestAsync(); - }); - // cleanup - try - { - Directory.Delete(outputDirectory); - } - catch (Exception) - { - // ignored - } - } - [Fact] public async Task GeneratesManifestWithMultipleSecuritySchemesAsync() { @@ -608,7 +567,7 @@ public async Task GeneratesManifestWithMultipleSecuritySchemesAsync() var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml"; await File.WriteAllTextAsync(simpleDescriptionPath, apiDescription); var mockLogger = new Mock>(); - var openApiDocumentDs = new OpenApiDocumentDownloadService(_httpClient, mockLogger.Object); + var openApiDocumentDs = new OpenApiDocumentDownloadService(_httpClient, _logger); var outputDirectory = Path.Combine(workingDirectory, "output"); var generationConfiguration = new GenerationConfiguration { @@ -627,7 +586,7 @@ public async Task GeneratesManifestWithMultipleSecuritySchemesAsync() var urlTreeNode = OpenApiUrlTreeNode.Create(openApiDocument, Constants.DefaultOpenApiLabel); var pluginsGenerationService = - new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory); + new PluginsGenerationService(openApiDocument, urlTreeNode, generationConfiguration, workingDirectory, _logger); await pluginsGenerationService.GenerateManifestAsync(); Assert.True(File.Exists(Path.Combine(outputDirectory, ManifestFileName))); @@ -813,8 +772,7 @@ public async Task MergesAllOfRequestBodyAsync(string content, Action>(); - var openAPIDocumentDS = new OpenApiDocumentDownloadService(_httpClient, mockLogger.Object); + var openAPIDocumentDS = new OpenApiDocumentDownloadService(_httpClient, _logger); var outputDirectory = Path.Combine(workingDirectory, "output"); var generationConfiguration = new GenerationConfiguration { @@ -829,7 +787,7 @@ public async Task MergesAllOfRequestBodyAsync(string content, Action x.Name.Equals("OtherProp")); Assert.Contains(model.Methods, x => x.Name.Equals("otherMethod")); Assert.Contains(model.Usings, x => x.Name.Equals("otherNs")); + Assert.Contains(model.StartBlock.Implements, x => x.Name.Equals("IAdditionalDataHolder")); } [Fact] public async Task AddsUsingsForErrorTypesForRequestExecutorAsync() diff --git a/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs index 19fcdca3b0..8d60a649fa 100644 --- a/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/GoLanguageRefinerTests.cs @@ -578,6 +578,11 @@ public async Task InlineParentOnErrorClassesWhichAlreadyInheritAsync() { Name = "otherNs", }); + otherModel.StartBlock.AddImplements(new CodeType + { + Name = "IAdditionalDataHolder", + IsExternal = true + }); var declaration = model.StartBlock; declaration.Inherits = new CodeType { @@ -588,6 +593,10 @@ public async Task InlineParentOnErrorClassesWhichAlreadyInheritAsync() Assert.Contains(model.Properties, x => x.Name.Equals("otherProp")); Assert.Contains(model.Methods, x => x.Name.Equals("otherMethod")); Assert.Contains(model.Usings, x => x.Name.Equals("otherNs")); + + var modelInterface = root.FindChildByName("somemodelable"); + Assert.NotNull(modelInterface); + Assert.Contains(modelInterface.StartBlock.Implements, x => x.Name.Equals("AdditionalDataHolder", StringComparison.OrdinalIgnoreCase)); } [Fact] public async Task AddsUsingsForErrorTypesForRequestExecutorAsync() @@ -1294,5 +1303,46 @@ public async Task AddsUsingForUntypedNodeInMethodParameterAsync() Assert.Single(nodeUsing); Assert.Equal("github.com/microsoft/kiota-abstractions-go/serialization", nodeUsing[0].Declaration.Name); } + [Theory] + [InlineData("ISODuration", false)] + [InlineData("DateOnly", false)] + [InlineData("TimeOnly", false)] + [InlineData("Time", false)] + [InlineData("DateTimeOffset", false)] + [InlineData("Guid", false)] + [InlineData("string", false)] + [InlineData("boolean", true)] + [InlineData("int64", true)] + [InlineData("integer", true)] + [InlineData("long", true)] + [InlineData("float", true)] + public async Task ImportsStrConvForRelevantTypesOnly(string pathParameterType, bool isImported) + { + var model = root.AddClass(new CodeClass + { + Name = "RequestBuilder", + Kind = CodeClassKind.RequestBuilder + }).First(); + var constructor = model.AddMethod(new CodeMethod + { + Name = "NewRequestBuilder", + Kind = CodeMethodKind.Constructor, + ReturnType = new CodeType + { + Name = "void" + } + }).First(); + constructor.AddParameter(new CodeParameter + { + Name = "daysInPast", + Kind = CodeParameterKind.Path, + Type = new CodeType + { + Name = pathParameterType + } + }); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Go }, root); + Assert.Equal(isImported, model.StartBlock.Usings.Any(static x => x.Declaration.Name.Equals("strconv", StringComparison.OrdinalIgnoreCase))); + } #endregion } diff --git a/tests/Kiota.Builder.Tests/Refiners/JavaLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/JavaLanguageRefinerTests.cs index 524926aeea..909acd7d41 100644 --- a/tests/Kiota.Builder.Tests/Refiners/JavaLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/JavaLanguageRefinerTests.cs @@ -84,6 +84,11 @@ public async Task InlineParentOnErrorClassesWhichAlreadyInheritAsync() { Name = "otherNs", }); + otherModel.StartBlock.AddImplements(new CodeType + { + Name = "IAdditionalDataHolder", + IsExternal = true + }); var declaration = model.StartBlock; declaration.Inherits = new CodeType { @@ -95,6 +100,7 @@ public async Task InlineParentOnErrorClassesWhichAlreadyInheritAsync() Assert.Contains(model.Methods, x => x.Name.Equals("otherMethod")); Assert.Contains(model.Usings, x => x.Name.Equals("otherNs")); Assert.Equal("ApiException", model.StartBlock.Inherits.Name); + Assert.Contains(model.StartBlock.Implements, x => x.Name.Equals("AdditionalDataHolder", StringComparison.OrdinalIgnoreCase)); } [Fact] public async Task AddsUsingsForErrorTypesForRequestExecutorAsync() diff --git a/tests/Kiota.Builder.Tests/Refiners/PythonLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/PythonLanguageRefinerTests.cs index 8da41e9c8c..320bca7a25 100644 --- a/tests/Kiota.Builder.Tests/Refiners/PythonLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/PythonLanguageRefinerTests.cs @@ -160,6 +160,11 @@ public async Task InlineParentOnErrorClassesWhichAlreadyInheritAsync() { Name = "otherNs", }); + otherModel.StartBlock.AddImplements(new CodeType + { + Name = "IAdditionalDataHolder", + IsExternal = true + }); var declaration = model.StartBlock; declaration.Inherits = new CodeType { @@ -170,6 +175,7 @@ public async Task InlineParentOnErrorClassesWhichAlreadyInheritAsync() Assert.Contains(model.Properties, x => x.Name.Equals("other_prop")); Assert.Contains(model.Methods, x => x.Name.Equals("other_method")); Assert.Contains(model.Usings, x => x.Name.Equals("otherNs")); + Assert.Contains(model.StartBlock.Implements, x => x.Name.Equals("AdditionalDataHolder", StringComparison.OrdinalIgnoreCase)); } [Fact] public async Task AddsUsingsForErrorTypesForRequestExecutorAsync() @@ -584,5 +590,34 @@ public async Task AddsPropertiesAndMethodTypesImportsPythonAsync() Assert.Single(requestBuilder.Methods, x => x.IsOfKind(CodeMethodKind.RequestExecutor)); Assert.DoesNotContain("QueryParameters", declaration.Usings.Select(x => x.Name)); } + [Fact] + public async Task ReplacesUntypedNodeInMethodParameterAndReturnTypeAsync() + { + var requestBuilderClass = root.AddClass(new CodeClass() { Name = "NodeRequestBuilder" }).First(); + var method = new CodeMethod + { + Name = "getAsync", + ReturnType = new CodeType() + { + Name = KiotaBuilder.UntypedNodeName,//Returns untyped node + IsExternal = true + }, + Kind = CodeMethodKind.RequestExecutor + }; + method.AddParameter(new CodeParameter() + { + Name = "jsonData", + Type = new CodeType() + { + Name = KiotaBuilder.UntypedNodeName, //Has untyped node parameter + IsExternal = true + }, + Kind = CodeParameterKind.RequestBody + }); + requestBuilderClass.AddMethod(method); + await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.Python }, root); + Assert.Equal("bytes", method.Parameters.First().Type.Name);// type is renamed to use the stream type + Assert.Equal("bytes", method.ReturnType.Name);// return type is renamed to use the stream type + } #endregion } diff --git a/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs b/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs index 540f49f10d..c0581cc2f1 100644 --- a/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs +++ b/tests/Kiota.Builder.Tests/Refiners/TypeScriptLanguageRefinerTests.cs @@ -177,16 +177,32 @@ public async Task InlineParentOnErrorClassesWhichAlreadyInheritAsync() new CodeUsing { Name = "otherNs", + }, + new CodeUsing + { + Name = "AdditionalDataHolder", }); + otherModel.StartBlock.AddImplements(new CodeType + { + Name = "AdditionalDataHolder", + IsExternal = true + }); model.StartBlock.Inherits = new CodeType { TypeDefinition = otherModel }; await ILanguageRefiner.RefineAsync(new GenerationConfiguration { Language = GenerationLanguage.TypeScript }, root); - Assert.DoesNotContain("otherProp", model.Properties.Select(static x => x.Name), StringComparer.OrdinalIgnoreCase); // we're not inlining since base error for TS is an interface - Assert.DoesNotContain("otherMethod", model.Methods.Select(static x => x.Name), StringComparer.OrdinalIgnoreCase); - Assert.DoesNotContain("otherNs", model.Usings.Select(static x => x.Name), StringComparer.OrdinalIgnoreCase); + var interfaceModel = root.FindChildByName("somemodel"); + Assert.NotNull(interfaceModel); + + Assert.DoesNotContain("otherProp", interfaceModel.Properties.Select(static x => x.Name), StringComparer.OrdinalIgnoreCase); // we're not inlining since base error for TS is an interface + Assert.DoesNotContain("otherMethod", interfaceModel.Methods.Select(static x => x.Name), StringComparer.OrdinalIgnoreCase); + Assert.DoesNotContain("otherNs", interfaceModel.Usings.Select(static x => x.Name), StringComparer.OrdinalIgnoreCase); + + var interfaceOtherModel = root.FindChildByName("otherModel"); + Assert.NotNull(interfaceOtherModel); + Assert.Contains(interfaceOtherModel.StartBlock.Implements, x => x.Name.Equals("AdditionalDataHolder", StringComparison.OrdinalIgnoreCase)); } [Fact] public async Task AddsUsingsForErrorTypesForRequestExecutorAsync() diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodeEnumWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodeEnumWriterTests.cs index 62ce1a24ec..609434152f 100644 --- a/tests/Kiota.Builder.Tests/Writers/Php/CodeEnumWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Php/CodeEnumWriterTests.cs @@ -52,7 +52,7 @@ public async Task WritesEnumAsync() Assert.Contains("use Microsoft\\Kiota\\Abstractions\\Enum", result); Assert.Contains("class", result); Assert.Contains("extends Enum", result); - Assert.Contains($"public const {optionName.ToUpperInvariant()} = '{optionName}'", result); + Assert.Contains($"public const {optionName.ToUpperInvariant()} = \"{optionName}\"", result); AssertExtensions.CurlyBracesAreClosed(result, 1); Assert.Contains(optionName, result); } diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs index fe01e34e07..ad5c54b056 100644 --- a/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Php/CodeMethodWriterTests.cs @@ -1474,9 +1474,11 @@ public void WritesModelFactoryBodyForUnionModels() Assert.Contains("if ('#kiota.complexType1' === $mappingValue) {", result); Assert.Contains("$result->setComplexType1Value(new ComplexType1())", result); Assert.Contains("if ($parseNode->getStringValue() !== null) {", result); - Assert.Contains("$result->setStringValue($parseNode->getStringValue())", result); + Assert.Contains("$finalValue = $parseNode->getStringValue()", result); + Assert.Contains("$result->setStringValue($finalValue)", result); Assert.Contains("else if ($parseNode->getCollectionOfObjectValues([ComplexType2::class, 'createFromDiscriminatorValue']) !== null) {", result); - Assert.Contains("$result->setComplexType2Value($parseNode->getCollectionOfObjectValues([ComplexType2::class, 'createFromDiscriminatorValue']))", result); + Assert.Contains("$finalValue = $parseNode->getCollectionOfObjectValues([ComplexType2::class, 'createFromDiscriminatorValue'])", result); + Assert.Contains("$result->setComplexType2Value($finalValue)", result); Assert.Contains("return $result", result); Assert.DoesNotContain("return new UnionTypeWrapper()", result); AssertExtensions.Before("$parseNode->getStringValue()", "getCollectionOfObjectValues([ComplexType2::class, 'createFromDiscriminatorValue'])", result); diff --git a/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs index a00225e813..4b96585405 100644 --- a/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Php/CodePropertyWriterTests.cs @@ -246,4 +246,26 @@ public async Task WriteRequestOptionAsync() Assert.Contains("@var array|null $options", result); Assert.Contains("public ?array $options = null;", result); } + + [Fact] + public void WritePropertyWithDescription() + { + CodeProperty property = new CodeProperty + { + Name = "name", + Documentation = new() + { + DescriptionTemplate = "The name pattern that branches must match in order to deploy to the environment.Wildcard characters will not match `/`. For example, to match branches that begin with `release/` and contain an additional single slash, use `release/*/*`.For more information about pattern matching syntax, see the [Ruby File.fnmatch documentation](https://ruby-doc.org/core-2.5.1/File.html#method-c-fnmatch).", + }, + Type = new CodeType + { + Name = "string" + }, + Access = AccessModifier.Private + }; + parentClass.AddProperty(property); + propertyWriter.WriteCodeElement(property, languageWriter); + var result = stringWriter.ToString(); + Assert.DoesNotContain("/*/*", result); + } } diff --git a/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs index ae6d75a3bc..2774185773 100644 --- a/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/Python/CodeMethodWriterTests.cs @@ -820,12 +820,13 @@ public void WritesUnionDeSerializerBody() Assert.Contains("return {}", result); } [Theory] - [InlineData(true, false, false, "string", "")] - [InlineData(false, true, false, "Stream", " \"Stream\",")] - [InlineData(false, false, true, "SomeEnum", " \"SomeEnum\",")] - [InlineData(false, false, false, "int", " int,")] - [InlineData(false, false, false, "CustomType", " CustomType,")] - public void GetTypeFactory_ReturnsCorrectString(bool isVoid, bool isStream, bool isEnum, string returnType, string expected) + [InlineData(true, false, false, false, "string", "")] + [InlineData(false, true, false, false, "Stream", " \"Stream\",")] + [InlineData(false, false, true, false, "SomeEnum", " \"SomeEnum\",")] + [InlineData(false, false, false, true, "int", " int,")] + [InlineData(false, false, false, false, "int", " \"int\",")] + [InlineData(false, false, false, false, "CustomType", " CustomType,")] + public void GetTypeFactory_ReturnsCorrectString(bool isVoid, bool isStream, bool isEnum, bool isCollection, string returnType, string expected) { var mockConventionService = new Mock(); @@ -835,9 +836,7 @@ public void GetTypeFactory_ReturnsCorrectString(bool isVoid, bool isStream, bool false // usesBackingStore ); - var result = codeMethodWriter.GetTypeFactory(isVoid, isStream, isEnum, returnType); - - + var result = codeMethodWriter.GetTypeFactory(isVoid, isStream, isEnum, returnType, isCollection); Assert.Equal(expected, result); } [Fact] @@ -1592,6 +1591,30 @@ public void WritesConstructor() Assert.DoesNotContain("get_path_parameters(", result); } [Fact] + public void EscapesCommentCharactersInDescription() + { + setup(); + method.Kind = CodeMethodKind.Constructor; + method.IsAsync = false; + parentClass.Kind = CodeClassKind.Custom; + parentClass.AddProperty(new CodeProperty + { + Name = "prop_without_default_value", + Kind = CodePropertyKind.Custom, + Documentation = new() + { + DescriptionTemplate = "This property has a description with comments \"\"\".", + }, + Type = new CodeType + { + Name = "string" + } + }); + writer.Write(method); + var result = tw.ToString(); + Assert.Contains("This property has a description with comments \\\"\\\"\\\".", result); + } + [Fact] public void WritesWithUrl() { setup(); diff --git a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs index 6eee533f97..79025ef0fa 100644 --- a/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs +++ b/tests/Kiota.Builder.Tests/Writers/TypeScript/CodeFunctionWriterTests.cs @@ -1116,6 +1116,23 @@ public async Task WritesConstructorWithEnumValueAsync() { Name = "pictureSize" }).First(); + + codeEnum.AddOption( + new CodeEnumOption + { + Name = "256x256", + SerializationName = "256x256" + }, + new CodeEnumOption + { + Name = "512x512", + SerializationName = "512x512" + }, + new CodeEnumOption + { + Name = "1024x1024", + SerializationName = "1024x1024" + }); parentClass.AddProperty(new CodeProperty { Name = propName, diff --git a/tests/Kiota.Tests/Kiota.Tests.csproj b/tests/Kiota.Tests/Kiota.Tests.csproj index 2ab181470b..b81a22368a 100644 --- a/tests/Kiota.Tests/Kiota.Tests.csproj +++ b/tests/Kiota.Tests/Kiota.Tests.csproj @@ -7,17 +7,17 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/vscode/microsoft-kiota/package-lock.json b/vscode/microsoft-kiota/package-lock.json index 36e4997ab2..d3a6ae335f 100644 --- a/vscode/microsoft-kiota/package-lock.json +++ b/vscode/microsoft-kiota/package-lock.json @@ -1,15 +1,15 @@ { "name": "kiota", - "version": "1.18.100000001", + "version": "1.21.100000001", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "kiota", - "version": "1.18.100000001", + "version": "1.21.100000001", "license": "MIT", "dependencies": { - "@vscode/extension-telemetry": "^0.9.7", + "@vscode/extension-telemetry": "^0.9.8", "@vscode/l10n": "^0.0.18", "adm-zip": "^0.5.16", "is-online": "^11.0.0", @@ -17,30 +17,30 @@ "vscode-jsonrpc": "^8.2.1" }, "devDependencies": { - "@stylistic/eslint-plugin-ts": "^2.10.1", - "@types/adm-zip": "^0.5.6", + "@stylistic/eslint-plugin-ts": "^2.12.1", + "@types/adm-zip": "^0.5.7", "@types/chai": "^5.0.1", - "@types/mocha": "^10.0.9", + "@types/mocha": "^10.0.10", "@types/node": "22.x", "@types/sinon": "^17.0.3", - "@types/vscode": "^1.95.0", - "@typescript-eslint/eslint-plugin": "^8.13.0", - "@typescript-eslint/parser": "^8.13.0", + "@types/vscode": "^1.96.0", + "@typescript-eslint/eslint-plugin": "^8.19.1", + "@typescript-eslint/parser": "^8.19.1", "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.4.1", "chai": "^5.1.2", - "eslint": "^9.14.0", + "eslint": "^9.17.0", "glob": "^11.0.0", - "mocha": "^10.8.2", + "mocha": "^11.0.1", "sinon": "^19.0.2", "ts-loader": "^9.5.1", "typemoq": "^2.1.0", - "typescript": "^5.6.3", - "webpack": "^5.96.1", - "webpack-cli": "^5.1.4" + "typescript": "^5.7.2", + "webpack": "^5.97.1", + "webpack-cli": "^6.0.1" }, "engines": { - "vscode": "^1.95.0" + "vscode": "^1.96.0" } }, "node_modules/@bcoe/v8-coverage": { @@ -51,13 +51,12 @@ "license": "MIT" }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz", + "integrity": "sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=14.17.0" } }, "node_modules/@eslint-community/eslint-utils": { @@ -103,11 +102,10 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.19.0.tgz", + "integrity": "sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.4", "debug": "^4.3.1", @@ -122,7 +120,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -133,7 +130,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -142,21 +138,19 @@ } }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", + "integrity": "sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.2.0.tgz", + "integrity": "sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==", "dev": true, - "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -180,7 +174,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -191,7 +184,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -200,11 +192,10 @@ } }, "node_modules/@eslint/js": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.17.0.tgz", + "integrity": "sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } @@ -214,17 +205,15 @@ "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", - "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "levn": "^0.4.1" }, @@ -285,11 +274,10 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.0.tgz", - "integrity": "sha512-xnRgu9DxZbkWak/te3fcytNyp8MTbuiZIaueg2rgEvBuN55n04nwLYLU9TX/VVlusc9L2ZNXi99nUFNkHXtr5g==", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", + "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -631,13 +619,13 @@ "license": "(Unlicense OR Apache-2.0)" }, "node_modules/@stylistic/eslint-plugin-ts": { - "version": "2.10.1", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.10.1.tgz", - "integrity": "sha512-XmXcixLPYfW0Z4Nf2ChnQ7CnfALNy/5gwNh22POiy64xreVYtiag4+yxN2SBEalEfoOAwDnqwDKam7e7XeoKTA==", + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-2.12.1.tgz", + "integrity": "sha512-Xx1NIioeW6LLlOfq5L/dLSrUXvi6q80UXDNbn/rXjKCzFT4a8wKwtp1q25kssdr1JEXI9a6tOHwFsh4Em+MoGg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^8.12.2", + "@typescript-eslint/utils": "^8.13.0", "eslint-visitor-keys": "^4.2.0", "espree": "^10.3.0" }, @@ -661,11 +649,10 @@ } }, "node_modules/@types/adm-zip": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.6.tgz", - "integrity": "sha512-lRlcSLg5Yoo7C2H2AUiAoYlvifWoCx/se7iUNiCBTfEVVYFVn+Tr9ZGed4K73tYgLe9O4PjdJvbxlkdAOx/qiw==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.7.tgz", + "integrity": "sha512-DNEs/QvmyRLurdQPChqq0Md4zGvPwHerAJYWk9l2jCbD1VPpnzRJorOdiq4zsw09NFbYnhfsoEhWtxIzXpn2yw==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -737,20 +724,18 @@ "license": "MIT" }, "node_modules/@types/mocha": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", - "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==", - "dev": true, - "license": "MIT" + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true }, "node_modules/@types/node": { - "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.5.tgz", + "integrity": "sha512-F8Q+SeGimwOo86fiovQh8qiXfFEh2/ocYv7tU5pJ3EXMSSxk1Joj5wefpFK2fHTf/N6HKGSxIDBT9f3gCxXPkQ==", "dev": true, - "license": "MIT", "dependencies": { - "undici-types": "~6.19.8" + "undici-types": "~6.20.0" } }, "node_modules/@types/sinon": { @@ -771,28 +756,26 @@ "license": "MIT" }, "node_modules/@types/vscode": { - "version": "1.95.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.95.0.tgz", - "integrity": "sha512-0LBD8TEiNbet3NvWsmn59zLzOFu/txSlGxnv5yAFHCrhG9WvAnR3IvfHzMOs2aeWqgvNjq9pO99IUw8d3n+unw==", - "dev": true, - "license": "MIT" + "version": "1.96.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz", + "integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==", + "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.13.0.tgz", - "integrity": "sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.19.1.tgz", + "integrity": "sha512-tJzcVyvvb9h/PB96g30MpxACd9IrunT7GF9wfA9/0TJ1LxGOJx1TdPzSbBBnNED7K9Ka8ybJsnEpiXPktolTLg==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/type-utils": "8.13.0", - "@typescript-eslint/utils": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/type-utils": "8.19.1", + "@typescript-eslint/utils": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -803,25 +786,20 @@ }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.13.0.tgz", - "integrity": "sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.19.1.tgz", + "integrity": "sha512-67gbfv8rAwawjYx3fYArwldTQKoYfezNUT4D5ioWetr/xCrxXxvleo3uuiFuKfejipvq+og7mjz3b0G2bVyUCw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "debug": "^4.3.4" }, "engines": { @@ -832,23 +810,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz", - "integrity": "sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.19.1.tgz", + "integrity": "sha512-60L9KIuN/xgmsINzonOcMDSB8p82h95hoBfSBtXuO4jlR1R9L1xSkmVZKgCPVfavDlXihh4ARNjXhh1gGnLC7Q==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0" + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -859,16 +832,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.13.0.tgz", - "integrity": "sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.19.1.tgz", + "integrity": "sha512-Rp7k9lhDKBMRJB/nM9Ksp1zs4796wVNyihG9/TU9R6KCJDNkQbc2EOKjrBtLYh3396ZdpXLtr/MkaSEmNMtykw==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.13.0", - "@typescript-eslint/utils": "8.13.0", + "@typescript-eslint/typescript-estree": "8.19.1", + "@typescript-eslint/utils": "8.19.1", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -877,18 +849,16 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/types": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.13.0.tgz", - "integrity": "sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.19.1.tgz", + "integrity": "sha512-JBVHMLj7B1K1v1051ZaMMgLW4Q/jre5qGK0Ew6UgXz1Rqh+/xPzV1aW581OM00X6iOfyr1be+QyW8LOUf19BbA==", "dev": true, - "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, @@ -898,20 +868,19 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz", - "integrity": "sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.19.1.tgz", + "integrity": "sha512-jk/TZwSMJlxlNnqhy0Eod1PNEvCkpY6MXOXE/WLlblZ6ibb32i2We4uByoKPv1d0OD2xebDv4hbs3fm11SMw8Q==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/visitor-keys": "8.13.0", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/visitor-keys": "8.19.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -920,23 +889,20 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.13.0.tgz", - "integrity": "sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.19.1.tgz", + "integrity": "sha512-IxG5gLO0Ne+KaUc8iW1A+XuKLd63o4wlbI1Zp692n1xojCl/THvgIKXJXBZixTh5dd5+yTJ/VXH7GJaaw21qXA==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.13.0", - "@typescript-eslint/types": "8.13.0", - "@typescript-eslint/typescript-estree": "8.13.0" + "@typescript-eslint/scope-manager": "8.19.1", + "@typescript-eslint/types": "8.19.1", + "@typescript-eslint/typescript-estree": "8.19.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -946,18 +912,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz", - "integrity": "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==", + "version": "8.19.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.19.1.tgz", + "integrity": "sha512-fzmjU8CHK853V/avYZAvuVut3ZTfwN5YtMaoi+X9Y9MA9keaWNHC3zEQ9zvyX/7Hj+5JkNyK1l7TOR2hevHB6Q==", "dev": true, - "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.13.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.19.1", + "eslint-visitor-keys": "^4.2.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -967,28 +933,14 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@vscode/extension-telemetry": { - "version": "0.9.7", - "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.9.7.tgz", - "integrity": "sha512-2GQbcfDUTg0QC1v0HefkHNwYrE5LYKzS3Zb0+uA6Qn1MBDzgiSh23ddOZF/JRqhqBFOG0mE70XslKSGQ5v9KwQ==", - "license": "MIT", + "version": "0.9.8", + "resolved": "https://registry.npmjs.org/@vscode/extension-telemetry/-/extension-telemetry-0.9.8.tgz", + "integrity": "sha512-7YcKoUvmHlIB8QYCE4FNzt3ErHi9gQPhdCM3ZWtpw1bxPT0I+lMdx52KHlzTNoJzQ2NvMX7HyzyDwBEiMgTrWQ==", "dependencies": { - "@microsoft/1ds-core-js": "^4.3.0", - "@microsoft/1ds-post-js": "^4.3.0", - "@microsoft/applicationinsights-web-basic": "^3.3.0" + "@microsoft/1ds-core-js": "^4.3.4", + "@microsoft/1ds-post-js": "^4.3.4", + "@microsoft/applicationinsights-web-basic": "^3.3.4" }, "engines": { "vscode": "^1.75.0" @@ -1024,6 +976,32 @@ "node": ">=18" } }, + "node_modules/@vscode/test-cli/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@vscode/test-cli/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@vscode/test-cli/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/@vscode/test-cli/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -1068,6 +1046,106 @@ "dev": true, "license": "ISC" }, + "node_modules/@vscode/test-cli/node_modules/mocha": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@vscode/test-cli/node_modules/mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/test-cli/node_modules/mocha/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@vscode/test-cli/node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@vscode/test-cli/node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@vscode/test-cli/node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -1085,6 +1163,58 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@vscode/test-cli/node_modules/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, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@vscode/test-cli/node_modules/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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@vscode/test-cli/node_modules/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, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@vscode/test-cli/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/@vscode/test-electron": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.4.1.tgz", @@ -1103,206 +1233,188 @@ } }, "node_modules/@webassemblyjs/ast": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", - "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" } }, "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" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true }, "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" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", - "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", - "dev": true, - "license": "MIT" + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", - "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.6", - "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", - "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", - "dev": true, - "license": "MIT" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", - "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", - "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", "dev": true, - "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", - "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", - "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", - "dev": true, - "license": "MIT" + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", - "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-opt": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1", - "@webassemblyjs/wast-printer": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", - "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", - "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-buffer": "1.12.1", - "@webassemblyjs/wasm-gen": "1.12.1", - "@webassemblyjs/wasm-parser": "1.12.1" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", - "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", - "@webassemblyjs/helper-api-error": "1.11.6", - "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/ieee754": "1.11.6", - "@webassemblyjs/leb128": "1.11.6", - "@webassemblyjs/utf8": "1.11.6" + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", - "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", "dev": true, - "license": "MIT", "dependencies": { - "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/ast": "1.14.1", "@xtuc/long": "4.2.2" } }, "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": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-3.0.1.tgz", + "integrity": "sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA==", "dev": true, - "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.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": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-3.0.1.tgz", + "integrity": "sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.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": "3.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-3.0.1.tgz", + "integrity": "sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg==", "dev": true, - "license": "MIT", "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "peerDependencies": { - "webpack": "5.x.x", - "webpack-cli": "5.x.x" + "webpack": "^5.82.0", + "webpack-cli": "6.x.x" }, "peerDependenciesMeta": { "webpack-dev-server": { @@ -1314,15 +1426,13 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/@xtuc/long": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true, - "license": "Apache-2.0" + "dev": true }, "node_modules/acorn": { "version": "8.14.0", @@ -1703,7 +1813,6 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -1981,7 +2090,6 @@ "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, - "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -2030,8 +2138,7 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/commander": { "version": "2.20.3", @@ -2074,11 +2181,10 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2246,7 +2352,6 @@ "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" }, @@ -2285,27 +2390,26 @@ } }, "node_modules/eslint": { - "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", + "version": "9.17.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz", + "integrity": "sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==", "dev": true, - "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.14.0", - "@eslint/plugin-kit": "^0.2.0", + "@eslint/config-array": "^0.19.0", + "@eslint/core": "^0.9.0", + "@eslint/eslintrc": "^3.2.0", + "@eslint/js": "9.17.0", + "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.0", + "@humanwhocodes/retry": "^0.4.1", "@types/estree": "^1.0.6", "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", "eslint-scope": "^8.2.0", @@ -2324,8 +2428,7 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" @@ -2529,7 +2632,6 @@ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 4.9.1" } @@ -2671,7 +2773,6 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2775,7 +2876,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=18" }, @@ -2837,7 +2937,6 @@ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, - "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -2952,7 +3051,6 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, - "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -2969,7 +3067,6 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, - "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -3030,7 +3127,6 @@ "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=10.13.0" } @@ -3061,11 +3157,10 @@ } }, "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, - "license": "MIT", "dependencies": { "hasown": "^2.0.2" }, @@ -3181,7 +3276,6 @@ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, - "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -3233,7 +3327,6 @@ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3411,7 +3504,6 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3652,11 +3744,10 @@ } }, "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.0.1.tgz", + "integrity": "sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==", "dev": true, - "license": "MIT", "dependencies": { "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", @@ -3665,7 +3756,7 @@ "diff": "^5.2.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", - "glob": "^8.1.0", + "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", @@ -3684,7 +3775,7 @@ "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/mocha/node_modules/ansi-regex": { @@ -3717,32 +3808,66 @@ "license": "MIT" }, "node_modules/mocha/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mocha/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" }, "funding": { "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/mocha/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 + }, "node_modules/mocha/node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, - "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -3750,6 +3875,22 @@ "node": ">=10" } }, + "node_modules/mocha/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/mocha/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -4137,7 +4278,6 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -4161,7 +4301,6 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, - "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -4203,8 +4342,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/path-scurry": { "version": "2.0.0", @@ -4268,7 +4406,6 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, - "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -4281,7 +4418,6 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4295,7 +4431,6 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, - "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -4308,7 +4443,6 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -4324,7 +4458,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -4464,7 +4597,6 @@ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", "dev": true, - "license": "MIT", "dependencies": { "resolve": "^1.20.0" }, @@ -4483,19 +4615,21 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, - "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4511,7 +4645,6 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, - "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -4524,7 +4657,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -4534,7 +4666,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -4674,7 +4805,6 @@ "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, - "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -4969,7 +5099,6 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -5102,13 +5231,6 @@ "node": "*" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/time-span": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", @@ -5138,16 +5260,15 @@ } }, "node_modules/ts-api-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", - "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.0.0.tgz", + "integrity": "sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/ts-loader": { @@ -5218,11 +5339,10 @@ } }, "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5232,11 +5352,10 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, - "license": "MIT" + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true }, "node_modules/update-browserslist-db": { "version": "1.1.1", @@ -5325,17 +5444,17 @@ } }, "node_modules/webpack": { - "version": "5.96.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", - "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", + "version": "5.97.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.1.tgz", + "integrity": "sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==", "dev": true, "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.6", - "@webassemblyjs/ast": "^1.12.1", - "@webassemblyjs/wasm-edit": "^1.12.1", - "@webassemblyjs/wasm-parser": "^1.12.1", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", "acorn": "^8.14.0", "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", @@ -5372,43 +5491,39 @@ } }, "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": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", + "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "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", + "@discoveryjs/json-ext": "^0.6.1", + "@webpack-cli/configtest": "^3.0.1", + "@webpack-cli/info": "^3.0.1", + "@webpack-cli/serve": "^3.0.1", "colorette": "^2.0.14", - "commander": "^10.0.1", + "commander": "^12.1.0", "cross-spawn": "^7.0.3", - "envinfo": "^7.7.3", + "envinfo": "^7.14.0", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^3.1.1", "rechoir": "^0.8.0", - "webpack-merge": "^5.7.3" + "webpack-merge": "^6.0.1" }, "bin": { "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">=14.15.0" + "node": ">=18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "5.x.x" + "webpack": "^5.82.0" }, "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, "webpack-bundle-analyzer": { "optional": true }, @@ -5418,28 +5533,26 @@ } }, "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": "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": ">=14" + "node": ">=18" } }, "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-6.0.1.tgz", + "integrity": "sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg==", "dev": true, - "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "flat": "^5.0.2", - "wildcard": "^2.0.0" + "wildcard": "^2.0.1" }, "engines": { - "node": ">=10.0.0" + "node": ">=18.0.0" } }, "node_modules/webpack-sources": { @@ -5496,8 +5609,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/word-wrap": { "version": "1.2.5", diff --git a/vscode/microsoft-kiota/package.json b/vscode/microsoft-kiota/package.json index a25b746d4b..4680ed82bd 100644 --- a/vscode/microsoft-kiota/package.json +++ b/vscode/microsoft-kiota/package.json @@ -3,12 +3,12 @@ "displayName": "Microsoft Kiota", "publisher": "ms-graph", "description": "Client generator for HTTP REST APIs described by OpenAPI which helps eliminate the need to take a dependency on a different API client for every API that you need to call, as well as limiting the generation to the exact API surface area you're interested in, thanks to a filtering capability.", - "version": "1.18.100000001", - "kiotaVersion": "1.18.0", + "version": "1.21.100000001", + "kiotaVersion": "1.22.0", "telemetryInstrumentationKey": "4c6357e0-daf9-42b5-bdfb-67878f8957b5", "icon": "images/logo.png", "engines": { - "vscode": "^1.95.0" + "vscode": "^1.96.0" }, "license": "MIT", "categories": [ @@ -217,12 +217,14 @@ "views": { "kiota-openapi-explorer": [ { - "id": "kiota.openApiExplorer", - "name": "%kiota.openApiExplorer.name%" + "id": "kiota.workspace", + "name": "%kiota.workspace.name%", + "order": 1 }, { - "id": "kiota.workspace", - "name": "%kiota.workspace.name%" + "id": "kiota.openApiExplorer", + "name": "%kiota.openApiExplorer.name%", + "order": 2 } ], "kiota-dependencies-info": [ @@ -301,6 +303,16 @@ "command": "kiota.openApiExplorer.removeAllFromSelectedEndpoints", "when": "view == kiota.openApiExplorer && viewItem != clientNameOrPluginName", "group": "inline@5" + }, + { + "command": "kiota.workspace.selectItem", + "when": "viewItem == item", + "group": "inline@1" + }, + { + "command": "kiota.workspace.deleteItem", + "when": "viewItem == item", + "group": "inline@2" } ], "commandPalette": [ @@ -437,6 +449,18 @@ { "command": "kiota.migrateFromLockFile", "title": "%kiota.migrateClients.title%" + }, + { + "command": "kiota.workspace.selectItem", + "title": "%kiota.openApiExplorer.editPaths.title%", + "category": "Kiota", + "icon": "$(bracket)" + }, + { + "command": "kiota.workspace.deleteItem", + "title": "%kiota.openApiExplorer.removeFromSelectedEndpoints.title%", + "category": "Kiota", + "icon": "$(trash)" } ], "languages": [ @@ -467,30 +491,30 @@ "test-with-coverage": "npm run pretest && vscode-test --coverage" }, "devDependencies": { - "@stylistic/eslint-plugin-ts": "^2.10.1", - "@types/adm-zip": "^0.5.6", + "@stylistic/eslint-plugin-ts": "^2.12.1", + "@types/adm-zip": "^0.5.7", "@types/chai": "^5.0.1", - "@types/mocha": "^10.0.9", + "@types/mocha": "^10.0.10", "@types/node": "22.x", "@types/sinon": "^17.0.3", - "@types/vscode": "^1.95.0", - "@typescript-eslint/eslint-plugin": "^8.13.0", - "@typescript-eslint/parser": "^8.13.0", + "@types/vscode": "^1.96.0", + "@typescript-eslint/eslint-plugin": "^8.19.1", + "@typescript-eslint/parser": "^8.19.1", "@vscode/test-cli": "^0.0.10", "@vscode/test-electron": "^2.4.1", "chai": "^5.1.2", - "eslint": "^9.14.0", + "eslint": "^9.17.0", "glob": "^11.0.0", - "mocha": "^10.8.2", + "mocha": "^11.0.1", "sinon": "^19.0.2", "ts-loader": "^9.5.1", "typemoq": "^2.1.0", - "typescript": "^5.6.3", - "webpack": "^5.96.1", - "webpack-cli": "^5.1.4" + "typescript": "^5.7.2", + "webpack": "^5.97.1", + "webpack-cli": "^6.0.1" }, "dependencies": { - "@vscode/extension-telemetry": "^0.9.7", + "@vscode/extension-telemetry": "^0.9.8", "@vscode/l10n": "^0.0.18", "adm-zip": "^0.5.16", "is-online": "^11.0.0", diff --git a/vscode/microsoft-kiota/package.nls.json b/vscode/microsoft-kiota/package.nls.json index 5c7baf619a..d1c0f02166 100644 --- a/vscode/microsoft-kiota/package.nls.json +++ b/vscode/microsoft-kiota/package.nls.json @@ -29,7 +29,7 @@ "kiota.openApiExplorer.openFile.title": "Open file", "kiota.workspace.name": "My Workspace", "kiota.openApiExplorer.regenerateButton.title": "Re-generate", - "kiota.openApiExplorer.editPaths.title": "Edit paths", + "kiota.openApiExplorer.editPaths.title": "Select", "kiota.openApiExplorer.refresh.title": "Refresh", "kiota.migrateClients.title": "Migrate API clients" } diff --git a/vscode/microsoft-kiota/src/commands/closeDescriptionCommand.ts b/vscode/microsoft-kiota/src/commands/closeDescriptionCommand.ts index f8e8a167d5..3f350d7585 100644 --- a/vscode/microsoft-kiota/src/commands/closeDescriptionCommand.ts +++ b/vscode/microsoft-kiota/src/commands/closeDescriptionCommand.ts @@ -18,7 +18,7 @@ export class CloseDescriptionCommand extends Command { public async execute(): Promise { const yesAnswer = vscode.l10n.t("Yes"); const response = await vscode.window.showInformationMessage( - vscode.l10n.t("Do you want to remove this API description?"), + vscode.l10n.t("Do you want to close this API description?"), yesAnswer, vscode.l10n.t("No") ); diff --git a/vscode/microsoft-kiota/src/commands/deleteWorkspaceItem/deleteWorkspaceItemCommand.ts b/vscode/microsoft-kiota/src/commands/deleteWorkspaceItem/deleteWorkspaceItemCommand.ts new file mode 100644 index 0000000000..4eb9b79c05 --- /dev/null +++ b/vscode/microsoft-kiota/src/commands/deleteWorkspaceItem/deleteWorkspaceItemCommand.ts @@ -0,0 +1,88 @@ +import TelemetryReporter from "@vscode/extension-telemetry"; +import * as vscode from "vscode"; + +import { extensionId } from "../../constants"; +import { getLogEntriesForLevel, KiotaLogEntry, LogLevel } from "../../kiotaInterop"; +import { OpenApiTreeProvider } from "../../providers/openApiTreeProvider"; +import { SharedService } from "../../providers/sharedService"; +import { WorkspaceTreeItem } from "../../providers/workspaceTreeProvider"; +import { isPluginType } from "../../util"; +import { exportLogsAndShowErrors } from "../../utilities/logging"; +import { Command } from "../Command"; +import { removeClient, removePlugin } from "./removeItem"; + +export class DeleteWorkspaceItemCommand extends Command { + constructor( + private _context: vscode.ExtensionContext, + private _openApiTreeProvider: OpenApiTreeProvider, + private _kiotaOutputChannel: vscode.LogOutputChannel, + private sharedService: SharedService + ) { + super(); + } + + public getName(): string { + return `${extensionId}.workspace.deleteItem`; + } + + public async execute(workspaceTreeItem: WorkspaceTreeItem): Promise { + const type = workspaceTreeItem.category && isPluginType(workspaceTreeItem.category) ? "plugin" : "client"; + const yesAnswer: vscode.MessageItem = { title: vscode.l10n.t("Yes") }; + const noAnswer: vscode.MessageItem = { title: vscode.l10n.t("No") }; + + const response = await vscode.window.showWarningMessage( + vscode.l10n.t("Do you want to delete this item?"), + yesAnswer, + noAnswer + ); + + if (response?.title === yesAnswer.title) { + if (this.sharedService.get('clientOrPluginKey') === workspaceTreeItem.label) { + this._openApiTreeProvider.closeDescription(); + } + + const result = await this.deleteItem(type, workspaceTreeItem); + if (result) { + const isSuccess = result.some(k => k.message.includes('removed successfully')); + await vscode.commands.executeCommand('kiota.workspace.refresh'); + if (isSuccess) { + void vscode.window.showInformationMessage(vscode.l10n.t('{0} removed successfully.', workspaceTreeItem.label)); + } else { + await exportLogsAndShowErrors(result, this._kiotaOutputChannel); + } + } + } + } + + private async deleteItem(type: string, workspaceTreeItem: WorkspaceTreeItem): Promise { + const itemName = workspaceTreeItem.label; + const result = await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + cancellable: false, + title: vscode.l10n.t(`Removing ${type}...`) + }, async (progress, _) => { + const start = performance.now(); + const result = type === "plugin" ? await removePlugin( + this._context, + itemName, + false, + ) : await removeClient( + this._context, + itemName, + false, + ); + const duration = performance.now() - start; + const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0; + const reporter = new TelemetryReporter(this._context.extension.packageJSON.telemetryInstrumentationKey); + reporter.sendRawTelemetryEvent(`${extensionId}.remove${type}.completed`, { + "pluginType": itemName, + "errorsCount": errorsCount.toString(), + }, { + "duration": duration, + }); + return result; + }); + return result; + } +} + diff --git a/vscode/microsoft-kiota/src/commands/deleteWorkspaceItem/removeItem.ts b/vscode/microsoft-kiota/src/commands/deleteWorkspaceItem/removeItem.ts new file mode 100644 index 0000000000..8b906d30e9 --- /dev/null +++ b/vscode/microsoft-kiota/src/commands/deleteWorkspaceItem/removeItem.ts @@ -0,0 +1,32 @@ +import * as vscode from "vscode"; +import * as rpc from "vscode-jsonrpc/node"; + +import { connectToKiota, KiotaLogEntry } from "../../kiotaInterop"; + +export function removePlugin(context: vscode.ExtensionContext, pluginName: string, cleanOutput: boolean): Promise { + return connectToKiota(context, async (connection) => { + const request = new rpc.RequestType2( + "RemovePlugin" + ); + const result = await connection.sendRequest( + request, + pluginName, + cleanOutput + ); + return result; + }); +}; + +export function removeClient(context: vscode.ExtensionContext, clientName: string, cleanOutput: boolean): Promise { + return connectToKiota(context, async (connection) => { + const request = new rpc.RequestType2( + "RemoveClient" + ); + const result = await connection.sendRequest( + request, + clientName, + cleanOutput + ); + return result; + }); +}; \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/commands/editPathsCommand.ts b/vscode/microsoft-kiota/src/commands/editPathsCommand.ts index 311215a8ab..e2eb7c6060 100644 --- a/vscode/microsoft-kiota/src/commands/editPathsCommand.ts +++ b/vscode/microsoft-kiota/src/commands/editPathsCommand.ts @@ -1,4 +1,6 @@ -import { extensionId, treeViewId } from "../constants"; +import * as vscode from 'vscode'; + +import { extensionId, SHOW_MESSAGE_AFTER_API_LOAD, treeViewId } from "../constants"; import { ClientOrPluginProperties } from "../kiotaInterop"; import { OpenApiTreeProvider } from "../providers/openApiTreeProvider"; import { WorkspaceGenerationContext } from "../types/WorkspaceGenerationContext"; @@ -8,11 +10,11 @@ import { Command } from "./Command"; export class EditPathsCommand extends Command { - private _openApiTreeProvider: OpenApiTreeProvider; - - public constructor(openApiTreeProvider: OpenApiTreeProvider) { + constructor( + private openApiTreeProvider: OpenApiTreeProvider, + private context: vscode.ExtensionContext + ) { super(); - this._openApiTreeProvider = openApiTreeProvider; } public getName(): string { @@ -21,11 +23,33 @@ export class EditPathsCommand extends Command { public async execute({ clientOrPluginKey, clientOrPluginObject }: Partial): Promise { await this.loadEditPaths(clientOrPluginKey!, clientOrPluginObject!); - this._openApiTreeProvider.resetInitialState(); - await updateTreeViewIcons(treeViewId, false, true); + this.openApiTreeProvider.resetInitialState(); } private async loadEditPaths(clientOrPluginKey: string, clientOrPluginObject: ClientOrPluginProperties) { - await openTreeViewWithProgress(() => this._openApiTreeProvider.loadEditPaths(clientOrPluginKey, clientOrPluginObject)); + await openTreeViewWithProgress( + async () => { + await this.openApiTreeProvider.loadEditPaths(clientOrPluginKey, clientOrPluginObject); + await updateTreeViewIcons(treeViewId, false, true); + await vscode.commands.executeCommand('kiota.workspace.refresh'); + } + ); + + const regenerateAnswer = vscode.l10n.t("Regenerate"); + const showGenerateMessage = this.context.globalState.get(SHOW_MESSAGE_AFTER_API_LOAD, true); + + if (showGenerateMessage) { + const doNotShowAgainOption = vscode.l10n.t("Do not show this again"); + const response = await vscode.window.showInformationMessage( + vscode.l10n.t('Click on Regenerate after selecting the paths in the API Explorer'), + regenerateAnswer, + doNotShowAgainOption + ); + if (response === regenerateAnswer) { + await vscode.commands.executeCommand(`kiota.regenerate`); + } else if (response === doNotShowAgainOption) { + await this.context.globalState.update(SHOW_MESSAGE_AFTER_API_LOAD, false); + } + } } } diff --git a/vscode/microsoft-kiota/src/commands/generate/generateClientCommand.ts b/vscode/microsoft-kiota/src/commands/generate/generateClientCommand.ts index 99b896ede6..e65cebaf85 100644 --- a/vscode/microsoft-kiota/src/commands/generate/generateClientCommand.ts +++ b/vscode/microsoft-kiota/src/commands/generate/generateClientCommand.ts @@ -15,31 +15,24 @@ import { GeneratedOutputState } from "../../types/GeneratedOutputState"; import { WorkspaceGenerationContext } from "../../types/WorkspaceGenerationContext"; import { getSanitizedString, getWorkspaceJsonDirectory, parseGenerationLanguage, parseGenerationType, parsePluginType, updateTreeViewIcons } from "../../util"; import { isDeeplinkEnabled, transformToGenerationConfig } from "../../utilities/deep-linking"; -import { exportLogsAndShowErrors } from "../../utilities/logging"; +import { checkForSuccess, exportLogsAndShowErrors, logFromLogLevel, showLogs } from "../../utilities/logging"; import { showUpgradeWarningMessage } from "../../utilities/messaging"; import { Command } from "../Command"; import { generateClient } from "./generateClient"; import { generatePlugin } from "./generatePlugin"; -import { checkForSuccess, displayGenerationResults } from "./generation-util"; +import { displayGenerationResults } from "./generation-util"; import { getLanguageInformation, getLanguageInformationForDescription } from "./getLanguageInformation"; export class GenerateClientCommand extends Command { - private _openApiTreeProvider: OpenApiTreeProvider; - private _context: vscode.ExtensionContext; - private _dependenciesViewProvider: DependenciesViewProvider; - private _setWorkspaceGenerationContext: (params: Partial) => void; constructor( - openApiTreeProvider: OpenApiTreeProvider, - context: vscode.ExtensionContext, - dependenciesViewProvider: DependenciesViewProvider, - setWorkspaceGenerationContext: (params: Partial) => void + private _openApiTreeProvider: OpenApiTreeProvider, + private _context: vscode.ExtensionContext, + private _dependenciesViewProvider: DependenciesViewProvider, + private _setWorkspaceGenerationContext: (params: Partial) => void, + private _kiotaOutputChannel: vscode.LogOutputChannel ) { super(); - this._openApiTreeProvider = openApiTreeProvider; - this._context = context; - this._dependenciesViewProvider = dependenciesViewProvider; - this._setWorkspaceGenerationContext = setWorkspaceGenerationContext; } public getName(): string { @@ -62,7 +55,7 @@ export class GenerateClientCommand extends Command { if (!deepLinkParams.name && this._openApiTreeProvider.apiTitle) { deepLinkParams.name = getSanitizedString(this._openApiTreeProvider.apiTitle); } - availableStateInfo = transformToGenerationConfig(deepLinkParams); + availableStateInfo = await transformToGenerationConfig(deepLinkParams); } else { const pluginName = getSanitizedString(this._openApiTreeProvider.apiTitle); availableStateInfo = { @@ -127,6 +120,23 @@ export class GenerateClientCommand extends Command { ); return; } + + const authenticationWarnings = getLogEntriesForLevel(result ?? [], LogLevel.warning).filter(entry => entry.message.startsWith('Authentication warning')); + if (authenticationWarnings.length > 0) { + authenticationWarnings.forEach(entry => logFromLogLevel(entry, this._kiotaOutputChannel)); + + const showLogs = vscode.l10n.t("Show logs"); + const response = await vscode.window.showWarningMessage( + vscode.l10n.t( + "Incompatible security schemes for Copilot usage detected in the selected endpoints."), + showLogs, + vscode.l10n.t("Cancel") + ); + if (response === showLogs) { + this._kiotaOutputChannel.show(); + } + } + if (result && getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length === 0) { // Save state before opening the new window const outputState = { @@ -162,6 +172,7 @@ export class GenerateClientCommand extends Command { } else { await displayGenerationResults(this._openApiTreeProvider, config); } + await vscode.commands.executeCommand('kiota.workspace.refresh'); } clearDeepLinkParams(); // Clear the state after successful generation @@ -190,6 +201,8 @@ export class GenerateClientCommand extends Command { settings.cleanOutput, settings.disableValidationRules, ConsumerOperation.Add, + undefined, + '', config.workingDirectory ); const duration = performance.now() - start; @@ -206,7 +219,7 @@ export class GenerateClientCommand extends Command { if (result) { const isSuccess = await checkForSuccess(result); if (!isSuccess) { - await exportLogsAndShowErrors(result); + await exportLogsAndShowErrors(result, this._kiotaOutputChannel); } void vscode.window.showInformationMessage(vscode.l10n.t('Generation completed successfully.')); } @@ -234,6 +247,8 @@ export class GenerateClientCommand extends Command { settings.cleanOutput, settings.disableValidationRules, ConsumerOperation.Add, + undefined, + '', config.workingDirectory ); const duration = performance.now() - start; @@ -250,7 +265,7 @@ export class GenerateClientCommand extends Command { if (result) { const isSuccess = await checkForSuccess(result); if (!isSuccess) { - await exportLogsAndShowErrors(result); + await exportLogsAndShowErrors(result, this._kiotaOutputChannel); } const deepLinkParams = getDeepLinkParams(); const isttkIntegration = deepLinkParams.source?.toLowerCase() === 'ttk'; @@ -320,7 +335,7 @@ export class GenerateClientCommand extends Command { if (result) { const isSuccess = await checkForSuccess(result); if (!isSuccess) { - await exportLogsAndShowErrors(result); + await exportLogsAndShowErrors(result, this._kiotaOutputChannel); } void vscode.window.showInformationMessage(vscode.l10n.t('Generation completed successfully.')); } diff --git a/vscode/microsoft-kiota/src/commands/generate/generatePlugin.ts b/vscode/microsoft-kiota/src/commands/generate/generatePlugin.ts index e4cb2b7b79..0cd6ef47b6 100644 --- a/vscode/microsoft-kiota/src/commands/generate/generatePlugin.ts +++ b/vscode/microsoft-kiota/src/commands/generate/generatePlugin.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; import * as rpc from "vscode-jsonrpc/node"; -import { connectToKiota, ConsumerOperation, GenerationConfiguration, KiotaLogEntry } from "../../kiotaInterop"; +import { connectToKiota, ConsumerOperation, GenerationConfiguration, KiotaLogEntry, PluginAuthType } from "../../kiotaInterop"; import { KiotaPluginType } from "../../types/enums"; import { getWorkspaceJsonDirectory } from "../../util"; @@ -16,7 +16,10 @@ export function generatePlugin(context: vscode.ExtensionContext, cleanOutput: boolean, disableValidationRules: string[], operation: ConsumerOperation, - workingDirectory: string = getWorkspaceJsonDirectory()): Promise { + pluginAuthType?: PluginAuthType | null, + pluginAuthRefid?: string, + workingDirectory: string = getWorkspaceJsonDirectory(), +): Promise { return connectToKiota(context, async (connection) => { const request = new rpc.RequestType1( "GeneratePlugin" @@ -24,16 +27,18 @@ export function generatePlugin(context: vscode.ExtensionContext, return await connection.sendRequest( request, { - pluginTypes: pluginTypes, - cleanOutput: cleanOutput, - clearCache: clearCache, - clientClassName: clientClassName, + pluginTypes, + cleanOutput, + clearCache, + clientClassName, disabledValidationRules: disableValidationRules, excludePatterns: excludeFilters, includePatterns: includeFilters, openAPIFilePath: descriptionPath, outputPath: output, - operation: operation + pluginAuthType, + pluginAuthRefid, + operation, } as GenerationConfiguration, ); }, workingDirectory); diff --git a/vscode/microsoft-kiota/src/commands/generate/generation-util.ts b/vscode/microsoft-kiota/src/commands/generate/generation-util.ts index a8782a072a..c372cb916f 100644 --- a/vscode/microsoft-kiota/src/commands/generate/generation-util.ts +++ b/vscode/microsoft-kiota/src/commands/generate/generation-util.ts @@ -1,28 +1,19 @@ import * as vscode from "vscode"; -import { treeViewId } from "../../constants"; -import { KiotaLogEntry } from "../../kiotaInterop"; +import { KIOTA_WORKSPACE_FILE, treeViewId } from "../../constants"; import { OpenApiTreeProvider } from "../../providers/openApiTreeProvider"; -import { getWorkspaceJsonPath, updateTreeViewIcons } from "../../util"; -import { loadWorkspaceFile } from "../../utilities/file"; - -export async function checkForSuccess(results: KiotaLogEntry[]) { - for (const result of results) { - if (result && result.message) { - if (result.message.includes("Generation completed successfully")) { - return true; - } - } - } - return false; -} +import { updateTreeViewIcons } from "../../util"; export async function displayGenerationResults(openApiTreeProvider: OpenApiTreeProvider, config: any) { const clientNameOrPluginName = config.clientClassName || config.pluginName; - openApiTreeProvider.refreshView(); - const workspaceJsonPath = getWorkspaceJsonPath(); - await loadWorkspaceFile({ fsPath: workspaceJsonPath }, openApiTreeProvider, clientNameOrPluginName); - await vscode.commands.executeCommand('kiota.workspace.refresh'); + const workspaceJson = vscode.workspace.textDocuments.find(doc => doc.fileName.endsWith(KIOTA_WORKSPACE_FILE)); + if (workspaceJson) { + const content = workspaceJson.getText(); + const workspace = JSON.parse(content); + const clientOrPluginObject = workspace.plugins[clientNameOrPluginName] || workspace.clients[clientNameOrPluginName]; + await openApiTreeProvider.loadEditPaths(clientNameOrPluginName, clientOrPluginObject); + } openApiTreeProvider.resetInitialState(); await updateTreeViewIcons(treeViewId, false, true); + await vscode.commands.executeCommand('kiota.workspace.refresh'); } \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/commands/openApidescription/searchOrOpenApiDescriptionCommand.ts b/vscode/microsoft-kiota/src/commands/openApidescription/searchOrOpenApiDescriptionCommand.ts index a701f233b7..a4eec01cc3 100644 --- a/vscode/microsoft-kiota/src/commands/openApidescription/searchOrOpenApiDescriptionCommand.ts +++ b/vscode/microsoft-kiota/src/commands/openApidescription/searchOrOpenApiDescriptionCommand.ts @@ -1,11 +1,12 @@ import TelemetryReporter from "@vscode/extension-telemetry"; import * as vscode from "vscode"; -import { extensionId, treeViewId } from "../../constants"; +import { extensionId, SHOW_MESSAGE_AFTER_API_LOAD, treeViewId } from "../../constants"; import { setDeepLinkParams } from "../../handlers/deepLinkParamsHandler"; import { searchSteps } from "../../modules/steps/searchSteps"; import { OpenApiTreeProvider } from "../../providers/openApiTreeProvider"; import { getExtensionSettings } from "../../types/extensionSettings"; +import { updateTreeViewIcons } from "../../util"; import { IntegrationParams, validateDeepLinkQueryParams } from "../../utilities/deep-linking"; import { openTreeViewWithProgress } from "../../utilities/progress"; import { Command } from "../Command"; @@ -13,13 +14,11 @@ import { searchDescription } from "./searchDescription"; export class SearchOrOpenApiDescriptionCommand extends Command { - private _openApiTreeProvider: OpenApiTreeProvider; - private _context: vscode.ExtensionContext; - - constructor(openApiTreeProvider: OpenApiTreeProvider, context: vscode.ExtensionContext) { + constructor( + private openApiTreeProvider: OpenApiTreeProvider, + private context: vscode.ExtensionContext + ) { super(); - this._openApiTreeProvider = openApiTreeProvider; - this._context = context; } public getName(): string { @@ -31,7 +30,7 @@ export class SearchOrOpenApiDescriptionCommand extends Command { if (Object.keys(searchParams).length > 0) { let [params, errorsArray] = validateDeepLinkQueryParams(searchParams); setDeepLinkParams(params); - const reporter = new TelemetryReporter(this._context.extension.packageJSON.telemetryInstrumentationKey); + const reporter = new TelemetryReporter(this.context.extension.packageJSON.telemetryInstrumentationKey); reporter.sendTelemetryEvent("DeepLinked searchOrOpenApiDescription", { "searchParameters": JSON.stringify(searchParams), "validationErrors": errorsArray.join(", ") @@ -40,7 +39,7 @@ export class SearchOrOpenApiDescriptionCommand extends Command { // proceed to enable loading of openapi description const yesAnswer = vscode.l10n.t("Yes, override it"); - if (this._openApiTreeProvider.hasChanges()) { + if (this.openApiTreeProvider.hasChanges()) { const response = await vscode.window.showWarningMessage( vscode.l10n.t( "Before adding a new API description, consider that your changes and current selection will be lost."), @@ -58,12 +57,32 @@ export class SearchOrOpenApiDescriptionCommand extends Command { title: vscode.l10n.t("Searching...") }, (progress, _) => { const settings = getExtensionSettings(extensionId); - return searchDescription(this._context, x, settings.clearCache); + return searchDescription(this.context, x, settings.clearCache); })); if (config.descriptionPath) { - await openTreeViewWithProgress(() => this._openApiTreeProvider.setDescriptionUrl(config.descriptionPath!)); + await openTreeViewWithProgress(async () => { + await this.openApiTreeProvider.setDescriptionUrl(config.descriptionPath!); + await updateTreeViewIcons(treeViewId, true, false); + }); + + const generateAnswer = vscode.l10n.t("Generate"); + const showGenerateMessage = this.context.globalState.get(SHOW_MESSAGE_AFTER_API_LOAD, true); + + if (showGenerateMessage) { + const doNotShowAgainOption = vscode.l10n.t("Do not show this again"); + const response = await vscode.window.showInformationMessage( + vscode.l10n.t('Click on Generate after selecting the paths in the API Explorer'), + generateAnswer, + doNotShowAgainOption + ); + + if (response === generateAnswer) { + await vscode.commands.executeCommand(`${treeViewId}.generateClient`); + } else if (response === doNotShowAgainOption) { + await this.context.globalState.update(SHOW_MESSAGE_AFTER_API_LOAD, false); + } + } } - await vscode.window.showInformationMessage(vscode.l10n.t('You can now select the required endpoints from {0}', this._openApiTreeProvider.apiTitle!)); } } diff --git a/vscode/microsoft-kiota/src/commands/regenerate/regenerate.service.ts b/vscode/microsoft-kiota/src/commands/regenerate/regenerate.service.ts index 139425d8ff..b9ca84c3ed 100644 --- a/vscode/microsoft-kiota/src/commands/regenerate/regenerate.service.ts +++ b/vscode/microsoft-kiota/src/commands/regenerate/regenerate.service.ts @@ -9,23 +9,14 @@ import { OpenApiTreeProvider } from "../../providers/openApiTreeProvider"; import { KiotaGenerationLanguage, KiotaPluginType } from "../../types/enums"; import { ExtensionSettings } from "../../types/extensionSettings"; import { parseGenerationLanguage, parsePluginType } from "../../util"; -import { exportLogsAndShowErrors } from "../../utilities/logging"; +import { checkForSuccess, exportLogsAndShowErrors } from "../../utilities/logging"; import { generateClient } from "../generate/generateClient"; import { generatePlugin } from "../generate/generatePlugin"; -import { checkForSuccess } from "../generate/generation-util"; export class RegenerateService { - private _context: ExtensionContext; - private _openApiTreeProvider: OpenApiTreeProvider; - private _clientKey: string; - private _clientObject: ClientOrPluginProperties; - public constructor(context: ExtensionContext, openApiTreeProvider: OpenApiTreeProvider, - clientKey: string, clientObject: ClientOrPluginProperties) { - this._context = context; - this._openApiTreeProvider = openApiTreeProvider; - this._clientKey = clientKey; - this._clientObject = clientObject; + public constructor(private _context: ExtensionContext, private _openApiTreeProvider: OpenApiTreeProvider, + private _clientKey: string, private _clientObject: ClientOrPluginProperties, private _kiotaOutputChannel: vscode.LogOutputChannel) { } async regenerateClient(settings: ExtensionSettings, selectedPaths?: string[]): Promise { @@ -62,7 +53,7 @@ export class RegenerateService { if (result) { const isSuccess = await checkForSuccess(result); if (!isSuccess) { - await exportLogsAndShowErrors(result); + await exportLogsAndShowErrors(result, this._kiotaOutputChannel); } void vscode.window.showInformationMessage(`Client ${this._clientKey} re-generated successfully.`); } @@ -92,7 +83,9 @@ export class RegenerateService { settings.clearCache, false, settings.disableValidationRules, - ConsumerOperation.Edit + ConsumerOperation.Edit, + pluginObjectItem.authType ? pluginObjectItem.authType : null, + pluginObjectItem.authReferenceId ? pluginObjectItem.authReferenceId : '', ); const duration = performance.now() - start; const errorsCount = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error).length : 0; @@ -107,7 +100,7 @@ export class RegenerateService { if (result) { const isSuccess = await checkForSuccess(result); if (!isSuccess) { - await exportLogsAndShowErrors(result); + await exportLogsAndShowErrors(result, this._kiotaOutputChannel); } void vscode.window.showInformationMessage(vscode.l10n.t(`Plugin ${this._clientKey} re-generated successfully.`)); } diff --git a/vscode/microsoft-kiota/src/commands/regenerate/regenerateButtonCommand.ts b/vscode/microsoft-kiota/src/commands/regenerate/regenerateButtonCommand.ts index 2830a072eb..7319264b44 100644 --- a/vscode/microsoft-kiota/src/commands/regenerate/regenerateButtonCommand.ts +++ b/vscode/microsoft-kiota/src/commands/regenerate/regenerateButtonCommand.ts @@ -12,13 +12,9 @@ import { Command } from "../Command"; import { RegenerateService } from "./regenerate.service"; export class RegenerateButtonCommand extends Command { - private _context: ExtensionContext; - private _openApiTreeProvider: OpenApiTreeProvider; - constructor(context: ExtensionContext, openApiTreeProvider: OpenApiTreeProvider) { + constructor(private _context: ExtensionContext, private _openApiTreeProvider: OpenApiTreeProvider, private _kiotaOutputChannel: vscode.LogOutputChannel) { super(); - this._context = context; - this._openApiTreeProvider = openApiTreeProvider; } public getName(): string { @@ -53,19 +49,19 @@ export class RegenerateButtonCommand extends Command { } const configObject = clientOrPluginObject || configuration; - const regenerateService = new RegenerateService(this._context, this._openApiTreeProvider, clientOrPluginKey, configObject); + const regenerateService = new RegenerateService(this._context, this._openApiTreeProvider, clientOrPluginKey, configObject, this._kiotaOutputChannel); if (isClientType(generationType)) { await regenerateService.regenerateClient(settings, selectedPaths); - + } + if (isPluginType(generationType)) { + await regenerateService.regeneratePlugin(settings, selectedPaths); const workspaceJson = vscode.workspace.textDocuments.find(doc => doc.fileName.endsWith(KIOTA_WORKSPACE_FILE)); if (workspaceJson && !workspaceJson.isDirty) { await regenerateService.regenerateTeamsApp(workspaceJson, clientOrPluginKey); } } - if (isPluginType(generationType)) { - await regenerateService.regeneratePlugin(settings, selectedPaths); - } + await vscode.commands.executeCommand('kiota.workspace.refresh'); } } \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/commands/regenerate/regenerateCommand.ts b/vscode/microsoft-kiota/src/commands/regenerate/regenerateCommand.ts index c28e1824d1..c4c0d673fc 100644 --- a/vscode/microsoft-kiota/src/commands/regenerate/regenerateCommand.ts +++ b/vscode/microsoft-kiota/src/commands/regenerate/regenerateCommand.ts @@ -11,13 +11,9 @@ import { Command } from "../Command"; import { RegenerateService } from "./regenerate.service"; export class RegenerateCommand extends Command { - private _context: ExtensionContext; - private _openApiTreeProvider: OpenApiTreeProvider; - constructor(context: ExtensionContext, openApiTreeProvider: OpenApiTreeProvider) { + constructor(private _context: ExtensionContext, private _openApiTreeProvider: OpenApiTreeProvider, private _kiotaOutputChannel: vscode.LogOutputChannel) { super(); - this._context = context; - this._openApiTreeProvider = openApiTreeProvider; } public getName(): string { @@ -40,15 +36,16 @@ export class RegenerateCommand extends Command { return; } - const regenerateService = new RegenerateService(this._context, this._openApiTreeProvider, clientOrPluginKey, clientOrPluginObject); + const regenerateService = new RegenerateService(this._context, this._openApiTreeProvider, clientOrPluginKey, clientOrPluginObject, this._kiotaOutputChannel); if (isClientType(generationType)) { await regenerateService.regenerateClient(settings); - if (workspaceJson) { - await regenerateService.regenerateTeamsApp(workspaceJson, clientOrPluginKey); - } } if (isPluginType(generationType)) { await regenerateService.regeneratePlugin(settings); + if (workspaceJson) { + await regenerateService.regenerateTeamsApp(workspaceJson, clientOrPluginKey); + } } + await vscode.commands.executeCommand('kiota.workspace.refresh'); } } \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/commands/updateClients/updateClientsCommand.ts b/vscode/microsoft-kiota/src/commands/updateClients/updateClientsCommand.ts index 2e05bd7692..7b517c15f6 100644 --- a/vscode/microsoft-kiota/src/commands/updateClients/updateClientsCommand.ts +++ b/vscode/microsoft-kiota/src/commands/updateClients/updateClientsCommand.ts @@ -9,13 +9,12 @@ import { Command } from "../Command"; import { updateClients } from './updateClients'; interface UpdateClientsCommandProps { - kiotaOutputChannel: vscode.LogOutputChannel; kiotaStatusBarItem: vscode.StatusBarItem; } export class UpdateClientsCommand extends Command { - constructor(private context: vscode.ExtensionContext) { + constructor(private context: vscode.ExtensionContext, private kiotaOutputChannel: vscode.LogOutputChannel) { super(); } @@ -23,7 +22,7 @@ export class UpdateClientsCommand extends Command { return `${extensionId}.updateClients`; } - public async execute({ kiotaOutputChannel, kiotaStatusBarItem }: UpdateClientsCommandProps): Promise { + public async execute({ kiotaStatusBarItem }: UpdateClientsCommandProps): Promise { if ( !vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0 @@ -37,11 +36,11 @@ export class UpdateClientsCommand extends Command { if (existingApiManifestFileUris.length > 0) { await Promise.all(existingApiManifestFileUris.map(uri => showUpgradeWarningMessage(uri, null, null, this.context))); } - await updateStatusBarItem(this.context, kiotaOutputChannel, kiotaStatusBarItem); + await updateStatusBarItem(this.context, this.kiotaOutputChannel, kiotaStatusBarItem); try { - kiotaOutputChannel.clear(); - kiotaOutputChannel.show(); - kiotaOutputChannel.info( + this.kiotaOutputChannel.clear(); + this.kiotaOutputChannel.show(); + this.kiotaOutputChannel.info( vscode.l10n.t("updating client with path {path}", { path: vscode.workspace.workspaceFolders[0].uri.fsPath, }) @@ -55,10 +54,10 @@ export class UpdateClientsCommand extends Command { return updateClients(this.context, settings.cleanOutput, settings.clearCache); }); if (res) { - await exportLogsAndShowErrors(res); + await exportLogsAndShowErrors(res, this.kiotaOutputChannel); } } catch (error) { - kiotaOutputChannel.error( + this.kiotaOutputChannel.error( vscode.l10n.t(`error updating the clients {error}`), error ); diff --git a/vscode/microsoft-kiota/src/constants.ts b/vscode/microsoft-kiota/src/constants.ts index 4c627f2e39..d8463811d1 100644 --- a/vscode/microsoft-kiota/src/constants.ts +++ b/vscode/microsoft-kiota/src/constants.ts @@ -15,3 +15,4 @@ export const APIMANIFEST = "apimanifest"; export const REMIND_ME_LATER_FLAG = 'remindMeLater'; export const API_MANIFEST_FILE = "apimanifest.json"; export const MANIFEST_KIOTA_VERSION_KEY = "x-ms-kiota-version"; +export const SHOW_MESSAGE_AFTER_API_LOAD = "show-message-after-api-load"; diff --git a/vscode/microsoft-kiota/src/extension.ts b/vscode/microsoft-kiota/src/extension.ts index 5728e823c7..19e9828adc 100644 --- a/vscode/microsoft-kiota/src/extension.ts +++ b/vscode/microsoft-kiota/src/extension.ts @@ -4,6 +4,7 @@ import TelemetryReporter from '@vscode/extension-telemetry'; import * as vscode from "vscode"; import { CloseDescriptionCommand } from './commands/closeDescriptionCommand'; +import { DeleteWorkspaceItemCommand } from './commands/deleteWorkspaceItem/deleteWorkspaceItemCommand'; import { EditPathsCommand } from './commands/editPathsCommand'; import { GenerateClientCommand } from './commands/generate/generateClientCommand'; import { displayGenerationResults } from './commands/generate/generation-util'; @@ -27,10 +28,12 @@ import { UriHandler } from './handlers/uriHandler'; import { ClientOrPluginProperties } from "./kiotaInterop"; +import { WorkspaceContentService } from './modules/workspace'; import { CodeLensProvider } from './providers/codelensProvider'; import { DependenciesViewProvider } from "./providers/dependenciesViewProvider"; import { OpenApiTreeNode, OpenApiTreeProvider } from "./providers/openApiTreeProvider"; -import { loadTreeView } from './providers/workspaceTreeProvider'; +import { SharedService } from './providers/sharedService'; +import { loadTreeView, WorkspaceTreeItem, WorkspaceTreeProvider } from './providers/workspaceTreeProvider'; import { getExtensionSettings } from "./types/extensionSettings"; import { GeneratedOutputState } from './types/GeneratedOutputState'; import { WorkspaceGenerationContext } from "./types/WorkspaceGenerationContext"; @@ -50,11 +53,14 @@ export async function activate( kiotaOutputChannel = vscode.window.createOutputChannel("Kiota", { log: true, }); - const openApiTreeProvider = new OpenApiTreeProvider(context, () => getExtensionSettings(extensionId)); + const sharedService = SharedService.getInstance(); + const workspaceContentService = new WorkspaceContentService(); + const openApiTreeProvider = new OpenApiTreeProvider(context, () => getExtensionSettings(extensionId), sharedService); const dependenciesInfoProvider = new DependenciesViewProvider( context.extensionUri ); const reporter = new TelemetryReporter(context.extension.packageJSON.telemetryInstrumentationKey); + const workspaceTreeProvider = new WorkspaceTreeProvider(workspaceContentService, sharedService); const setWorkspaceGenerationContext = (params: Partial) => { workspaceGenerationContext = { ...workspaceGenerationContext, ...params }; @@ -68,17 +74,18 @@ export async function activate( const removeFromSelectedEndpointsCommand = new RemoveFromSelectedEndpointsCommand(openApiTreeProvider); const filterDescriptionCommand = new FilterDescriptionCommand(openApiTreeProvider); const openDocumentationPageCommand = new OpenDocumentationPageCommand(); - const editPathsCommand = new EditPathsCommand(openApiTreeProvider); + const editPathsCommand = new EditPathsCommand(openApiTreeProvider, context); const searchOrOpenApiDescriptionCommand = new SearchOrOpenApiDescriptionCommand(openApiTreeProvider, context); - const generateClientCommand = new GenerateClientCommand(openApiTreeProvider, context, dependenciesInfoProvider, setWorkspaceGenerationContext); - const regenerateCommand = new RegenerateCommand(context, openApiTreeProvider); - const regenerateButtonCommand = new RegenerateButtonCommand(context, openApiTreeProvider); + const generateClientCommand = new GenerateClientCommand(openApiTreeProvider, context, dependenciesInfoProvider, setWorkspaceGenerationContext, kiotaOutputChannel); + const regenerateCommand = new RegenerateCommand(context, openApiTreeProvider, kiotaOutputChannel); + const regenerateButtonCommand = new RegenerateButtonCommand(context, openApiTreeProvider, kiotaOutputChannel); const closeDescriptionCommand = new CloseDescriptionCommand(openApiTreeProvider); const statusCommand = new StatusCommand(); const selectLockCommand = new SelectLockCommand(openApiTreeProvider); - const updateClientsCommand = new UpdateClientsCommand(context); + const deleteWorkspaceItemCommand = new DeleteWorkspaceItemCommand(context, openApiTreeProvider, kiotaOutputChannel, sharedService); + const updateClientsCommand = new UpdateClientsCommand(context, kiotaOutputChannel); - await loadTreeView(context); + await loadTreeView(context, workspaceTreeProvider); await checkForLockFileAndPrompt(context); let codeLensProvider = new CodeLensProvider(); context.subscriptions.push( @@ -125,6 +132,8 @@ export async function activate( await regenerateCommand.execute({ clientOrPluginKey, clientOrPluginObject, generationType }); }), registerCommandWithTelemetry(reporter, migrateFromLockFileCommand.getName(), async (uri: vscode.Uri) => await migrateFromLockFileCommand.execute(uri)), + registerCommandWithTelemetry(reporter, deleteWorkspaceItemCommand.getName(), async (workspaceTreeItem: WorkspaceTreeItem) => await deleteWorkspaceItemCommand.execute(workspaceTreeItem)), + ); // create a new status bar item that we can now manage @@ -137,7 +146,7 @@ export async function activate( // update status bar item once at start await updateStatusBarItem(context, kiotaOutputChannel, kiotaStatusBarItem); - context.subscriptions.push(vscode.commands.registerCommand(updateClientsCommand.getName(), async () => await updateClientsCommand.execute({ kiotaOutputChannel, kiotaStatusBarItem }))); + context.subscriptions.push(vscode.commands.registerCommand(updateClientsCommand.getName(), async () => await updateClientsCommand.execute({ kiotaStatusBarItem }))); } function registerCommandWithTelemetry(reporter: TelemetryReporter, command: string, callback: (...args: any[]) => any, thisArg?: any): vscode.Disposable { diff --git a/vscode/microsoft-kiota/src/kiotaInterop/index.ts b/vscode/microsoft-kiota/src/kiotaInterop/index.ts index 3eb5adcda2..490780d03b 100644 --- a/vscode/microsoft-kiota/src/kiotaInterop/index.ts +++ b/vscode/microsoft-kiota/src/kiotaInterop/index.ts @@ -24,6 +24,7 @@ export async function connectToKiota(context: vscode.ExtensionContext, callba try { return await callback(connection); } catch (error) { + console.warn(error); const errorMessage = (error as { data?: { message: string } })?.data?.message || 'An unknown error occurred'; vscode.window.showErrorMessage(errorMessage); @@ -248,6 +249,13 @@ export interface GenerationConfiguration { usesBackingStore: boolean; pluginTypes: KiotaPluginType[]; operation: ConsumerOperation; + pluginAuthRefid?: string; + pluginAuthType?: PluginAuthType | null; +} + +export enum PluginAuthType { + oAuthPluginVault = "OAuthPluginVault", + apiKeyPluginVault = "ApiKeyPluginVault" } interface WorkspaceObjectProperties { @@ -269,6 +277,8 @@ export interface ClientObjectProperties extends WorkspaceObjectProperties { export interface PluginObjectProperties extends WorkspaceObjectProperties { types: string[]; + authType?: PluginAuthType, + authReferenceId?: string; } -export type ClientOrPluginProperties = ClientObjectProperties | PluginObjectProperties; +export type ClientOrPluginProperties = ClientObjectProperties | PluginObjectProperties; \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/modules/steps/index.ts b/vscode/microsoft-kiota/src/modules/steps/index.ts index 92441f98b5..fcfbd17b7b 100644 --- a/vscode/microsoft-kiota/src/modules/steps/index.ts +++ b/vscode/microsoft-kiota/src/modules/steps/index.ts @@ -113,7 +113,7 @@ export class MultiStepInput { input.title = title; input.step = step; input.totalSteps = totalSteps; - input.ignoreFocusOut = ignoreFocusOut ?? false; + input.ignoreFocusOut = ignoreFocusOut ?? true; input.placeholder = placeholder; input.items = items; input.buttons = [ @@ -160,7 +160,7 @@ export class MultiStepInput { input.totalSteps = totalSteps; input.value = value || ''; input.prompt = prompt; - input.ignoreFocusOut = ignoreFocusOut ?? false; + input.ignoreFocusOut = ignoreFocusOut ?? true; input.placeholder = placeholder; input.buttons = [ ...(this.steps.length > 1 ? [QuickInputButtons.Back] : []), diff --git a/vscode/microsoft-kiota/src/modules/workspace/index.ts b/vscode/microsoft-kiota/src/modules/workspace/index.ts new file mode 100644 index 0000000000..a7c863ab8e --- /dev/null +++ b/vscode/microsoft-kiota/src/modules/workspace/index.ts @@ -0,0 +1,9 @@ +import { ClientOrPluginProperties } from "../../kiotaInterop"; +import WorkspaceContentService from "./workspaceContentService"; + +export interface WorkspaceContent { + version: string; + clients: Record; + plugins: Record; +} +export { WorkspaceContentService }; diff --git a/vscode/microsoft-kiota/src/modules/workspace/workspaceContentService.ts b/vscode/microsoft-kiota/src/modules/workspace/workspaceContentService.ts new file mode 100644 index 0000000000..1ea61a6882 --- /dev/null +++ b/vscode/microsoft-kiota/src/modules/workspace/workspaceContentService.ts @@ -0,0 +1,38 @@ +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as fs from 'fs'; + +import { WorkspaceContent } from "."; +import { getWorkspaceJsonPath } from '../../util'; + +class WorkspaceContentService { + constructor() { } + + public async load(): Promise { + const isWorkspacePresent = await this.isKiotaWorkspaceFilePresent(); + if (!isWorkspacePresent) { + return; + } + try { + const content = await fs.promises.readFile(getWorkspaceJsonPath(), 'utf-8'); + return JSON.parse(content); + } catch (error) { + console.error('Error loading workspace.json:', error); + } + } + + async isKiotaWorkspaceFilePresent(): Promise { + if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0) { + return false; + } + const workspaceFileDir = path.resolve(getWorkspaceJsonPath()); + try { + await fs.promises.access(workspaceFileDir); + } catch (error) { + return false; + } + return true; + } +} + +export default WorkspaceContentService; \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/providers/openApiTreeProvider.ts b/vscode/microsoft-kiota/src/providers/openApiTreeProvider.ts index 26386edcb1..9e0435c13b 100644 --- a/vscode/microsoft-kiota/src/providers/openApiTreeProvider.ts +++ b/vscode/microsoft-kiota/src/providers/openApiTreeProvider.ts @@ -21,20 +21,24 @@ import { } from '../kiotaInterop'; import { ExtensionSettings } from '../types/extensionSettings'; import { updateTreeViewIcons } from '../util'; +import { SharedService } from './sharedService'; export class OpenApiTreeProvider implements vscode.TreeDataProvider { private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; public apiTitle?: string; private initialStateHash: string = ''; + constructor( private readonly context: vscode.ExtensionContext, private readonly settingsGetter: () => ExtensionSettings, + private readonly sharedService: SharedService, private _descriptionUrl?: string, public includeFilters: string[] = [], - public excludeFilters: string[] = []) { - + public excludeFilters: string[] = [], + ) { } + private _workspaceFilePath?: string; private _workspaceFile?: ConfigurationFile | Partial = {}; public get isWorkspaceFileLoaded(): boolean { @@ -332,6 +336,7 @@ export class OpenApiTreeProvider implements vscode.TreeDataProvider = new Map(); + + private constructor() { } + + public static getInstance(): SharedService { + if (!SharedService.instance) { + SharedService.instance = new SharedService(); + } + return SharedService.instance; + } + + public get(key: K): SharedState[K] | undefined { + return this.state.get(key); + } + + public set(key: K, value: SharedState[K]): void { + this.state.set(key, value); + } + + public clear(key: K): void { + this.state.delete(key); + } + + // Method to reset the singleton instance for testing + public static resetInstance(): void { + SharedService.instance = new SharedService(); + } +} \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/providers/workspaceTreeProvider.ts b/vscode/microsoft-kiota/src/providers/workspaceTreeProvider.ts index 0f7ec33fa7..51563edfdf 100644 --- a/vscode/microsoft-kiota/src/providers/workspaceTreeProvider.ts +++ b/vscode/microsoft-kiota/src/providers/workspaceTreeProvider.ts @@ -1,71 +1,143 @@ import * as vscode from 'vscode'; -import * as path from 'path'; -import * as fs from 'fs'; - -import { KIOTA_WORKSPACE_FILE } from '../constants'; -import { getWorkspaceJsonPath } from '../util'; - -export class WorkspaceTreeProvider implements vscode.TreeDataProvider { - public isWSPresent: boolean; - private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); - readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; - constructor(isWSPresent: boolean) { - this.isWSPresent = isWSPresent; + +import { CLIENTS, KIOTA_WORKSPACE_FILE, PLUGINS } from '../constants'; +import { ClientOrPluginProperties } from '../kiotaInterop'; +import { WorkspaceContent, WorkspaceContentService } from '../modules/workspace'; +import { getWorkspaceJsonPath, isClientType, isPluginType } from '../util'; +import { SharedService } from './sharedService'; + +export class WorkspaceTreeItem extends vscode.TreeItem { + constructor( + public readonly label: string, + public readonly collapsibleState: vscode.TreeItemCollapsibleState, + public readonly type: 'root' | 'category' | 'item' | 'info', + public readonly category?: string, + public readonly properties?: ClientOrPluginProperties, + public command?: vscode.Command + ) { + super(label, collapsibleState); + this.contextValue = type; + } +} + +export class WorkspaceTreeProvider implements vscode.TreeDataProvider { + private _onDidChangeTreeData: vscode.EventEmitter = new vscode.EventEmitter(); + readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; + private workspaceContent: WorkspaceContent | undefined = undefined; + + constructor( + private workspaceContentService: WorkspaceContentService, + private sharedService: SharedService + ) { } async refreshView(): Promise { + await this.loadContent(); this._onDidChangeTreeData.fire(); } - async getChildren(element?: vscode.TreeItem): Promise { - if (!this.isWSPresent) { + async loadContent(): Promise { + this.workspaceContent = await this.workspaceContentService.load(); + } + + async getChildren(element?: WorkspaceTreeItem): Promise { + if (!this.workspaceContent) { return []; } + if (!element) { - return [new vscode.TreeItem(KIOTA_WORKSPACE_FILE, vscode.TreeItemCollapsibleState.None)]; + const hasClients = this.workspaceContent.clients && Object.keys(this.workspaceContent.clients).length > 0; + const hasPlugins = this.workspaceContent.plugins && Object.keys(this.workspaceContent.plugins).length > 0; + const hasWorkspaceContent = hasClients || hasPlugins; + return hasWorkspaceContent ? [ + new WorkspaceTreeItem(KIOTA_WORKSPACE_FILE, + vscode.TreeItemCollapsibleState.Expanded, 'root') + ] : [ + new WorkspaceTreeItem(vscode.l10n.t('No clients or plugins are available'), + vscode.TreeItemCollapsibleState.None, 'info') + ]; + } + + if (this.workspaceContent) { + if (element.label === KIOTA_WORKSPACE_FILE) { + const children: WorkspaceTreeItem[] = []; + if (Object.keys(this.workspaceContent.clients).length > 0) { + children.push(new WorkspaceTreeItem(CLIENTS, vscode.TreeItemCollapsibleState.Expanded, 'category')); + } + if (Object.keys(this.workspaceContent.plugins).length > 0) { + children.push(new WorkspaceTreeItem(PLUGINS, vscode.TreeItemCollapsibleState.Expanded, 'category')); + } + return children; + } + + if (isClientType(element.label)) { + return Object.keys(this.workspaceContent.clients).map(clientName => + new WorkspaceTreeItem(clientName, vscode.TreeItemCollapsibleState.None, 'item', CLIENTS, this.getProperties(clientName, CLIENTS)) + ); + } + + if (isPluginType(element.label)) { + return Object.keys(this.workspaceContent.plugins).map(pluginName => + new WorkspaceTreeItem(pluginName, vscode.TreeItemCollapsibleState.None, 'item', PLUGINS, this.getProperties(pluginName, PLUGINS)) + ); + } } return []; } - getTreeItem(element: vscode.TreeItem): vscode.TreeItem { - if (element) { - element.command = { - command: 'kiota.workspace.openWorkspaceFile', - title: vscode.l10n.t("Open File"), - arguments: [vscode.Uri.file(getWorkspaceJsonPath())] - }; - element.contextValue = 'file'; + getProperties(name: string, category: string): ClientOrPluginProperties | undefined { + if (category && category === CLIENTS) { + return this.workspaceContent?.clients[name]; + } + return this.workspaceContent?.plugins[name]; + } + + getTreeItem(element: WorkspaceTreeItem): WorkspaceTreeItem { + if (!element) { + return element; + } + + switch (element.type) { + case 'root': + element.command = { + command: 'kiota.workspace.openWorkspaceFile', + title: vscode.l10n.t('Open File'), + arguments: [vscode.Uri.file(getWorkspaceJsonPath())] + }; + element.contextValue = 'folder'; + break; + + case 'item': + const key = element.label; + const clientOrPluginKey = this.sharedService.get('clientOrPluginKey'); + element.iconPath = (clientOrPluginKey && clientOrPluginKey === key) ? + new vscode.ThemeIcon('folder-opened') : + new vscode.ThemeIcon('folder'); + break; } return element; } + } async function openResource(resource: vscode.Uri): Promise { await vscode.window.showTextDocument(resource); } -async function isKiotaWorkspaceFilePresent(): Promise { - if (!vscode.workspace.workspaceFolders || vscode.workspace.workspaceFolders.length === 0) { - return false; - } - const workspaceFileDir = path.resolve(getWorkspaceJsonPath()); - try { - await fs.promises.access(workspaceFileDir); - } catch (error) { - return false; - } - return true; -} -export async function loadTreeView(context: vscode.ExtensionContext): Promise { - const treeDataProvider = new WorkspaceTreeProvider(await isKiotaWorkspaceFilePresent()); +export async function loadTreeView(context: vscode.ExtensionContext, treeDataProvider: WorkspaceTreeProvider): Promise { context.subscriptions.push(vscode.workspace.onDidChangeWorkspaceFolders(async () => { - treeDataProvider.isWSPresent = await isKiotaWorkspaceFilePresent(); await vscode.commands.executeCommand('kiota.workspace.refresh'); // Refresh the tree view when workspace folders change })); context.subscriptions.push(vscode.window.createTreeView('kiota.workspace', { treeDataProvider })); context.subscriptions.push(vscode.commands.registerCommand('kiota.workspace.openWorkspaceFile', openResource)); context.subscriptions.push(vscode.commands.registerCommand('kiota.workspace.refresh', async () => { - treeDataProvider.isWSPresent = await isKiotaWorkspaceFilePresent(); await treeDataProvider.refreshView(); })); -} + context.subscriptions.push( + vscode.commands.registerCommand('kiota.workspace.selectItem', async (workspaceTreeItem: WorkspaceTreeItem) => { + const { label, properties, category } = workspaceTreeItem; + await vscode.commands.executeCommand('kiota.editPaths', label, properties, category); + }) + ); + await vscode.commands.executeCommand('kiota.workspace.refresh'); +}; \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/test/suite/commands/deleteWorkspaceItemCommand.test.ts b/vscode/microsoft-kiota/src/test/suite/commands/deleteWorkspaceItemCommand.test.ts new file mode 100644 index 0000000000..9b6debfb39 --- /dev/null +++ b/vscode/microsoft-kiota/src/test/suite/commands/deleteWorkspaceItemCommand.test.ts @@ -0,0 +1,47 @@ +import assert from "assert"; +import * as sinon from "sinon"; +import * as vscode from 'vscode'; + +import { DeleteWorkspaceItemCommand } from '../../../commands/deleteWorkspaceItem/deleteWorkspaceItemCommand'; +import * as treeModule from "../../../providers/openApiTreeProvider"; +import * as sharedServiceModule from '../../../providers/sharedService'; +import { WorkspaceTreeItem } from '../../../providers/workspaceTreeProvider'; + +suite('DeleteWorkspaceItemCommand Tests', () => { + let context: vscode.ExtensionContext; + let outputChannel: vscode.LogOutputChannel; + let command: DeleteWorkspaceItemCommand; + let workspaceTreeItem: WorkspaceTreeItem; + + setup(() => { + context = { extension: { packageJSON: { telemetryInstrumentationKey: 'test-key' } } } as any; + outputChannel = { appendLine: sinon.stub() } as any; + var treeProvider = sinon.createStubInstance(treeModule.OpenApiTreeProvider); + var stubbedSharedService = sinon.createStubInstance(sharedServiceModule.SharedService); + command = new DeleteWorkspaceItemCommand(context, treeProvider, outputChannel, stubbedSharedService,); + workspaceTreeItem = { label: 'test-item', category: 'plugin' } as any; + }); + + teardown(() => { + sinon.restore(); + }); + + test('getName should return correct command name', () => { + assert.strictEqual("kiota.workspace.deleteItem", command.getName()); + }); + + test('execute should show success message and refresh workspace on success', async () => { + const yesAnswer: vscode.MessageItem = { title: vscode.l10n.t("Yes") }; + + const showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').resolves(yesAnswer); + const showInformationMessageStub = sinon.stub(vscode.window, 'showInformationMessage').resolves(); + const deleteItemStub = sinon.stub(command as any, 'deleteItem').resolves([{ message: 'removed successfully' }]); + + await command.execute(workspaceTreeItem); + + assert.strictEqual(showWarningMessageStub.calledOnce, true); + assert.strictEqual(showInformationMessageStub.calledOnce, true); + assert.strictEqual(deleteItemStub.calledOnce, true); + }); + +}); \ No newline at end of file diff --git a/vscode/microsoft-kiota/src/test/suite/commands/generateClientCommand.test.ts b/vscode/microsoft-kiota/src/test/suite/commands/generateClientCommand.test.ts index 7f15478fb7..5f7b4de9ee 100644 --- a/vscode/microsoft-kiota/src/test/suite/commands/generateClientCommand.test.ts +++ b/vscode/microsoft-kiota/src/test/suite/commands/generateClientCommand.test.ts @@ -75,7 +75,9 @@ const setWorkspaceGenerationContext = (params: Partial { const sanbox = sinon.createSandbox(); - + let myOutputChannel = vscode.window.createOutputChannel("Kiota", { + log: true, + }); teardown(() => { sanbox.restore(); }); @@ -83,7 +85,7 @@ suite('GenerateClientCommand Test Suite', () => { test('test function getName of GenerateClientCommand', () => { var treeProvider = sinon.createStubInstance(treeModule.OpenApiTreeProvider); var viewProvider = sinon.createStubInstance(dependenciesModule.DependenciesViewProvider); - const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext); + const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext, myOutputChannel); assert.strictEqual("kiota.openApiExplorer.generateClient", generateClientCommand.getName()); }); @@ -92,7 +94,7 @@ suite('GenerateClientCommand Test Suite', () => { treeProvider.getSelectedPaths.returns([]); var viewProvider = sinon.createStubInstance(dependenciesModule.DependenciesViewProvider); const vscodeWindowSpy = sinon.stub(vscode.window, "showErrorMessage"); - const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext); + const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext, myOutputChannel); await generateClientCommand.execute(); assert.strictEqual((treeProvider.getSelectedPaths()).length, 0); sinon.assert.calledOnceWithMatch(vscodeWindowSpy, vscode.l10n.t("No endpoints selected, select endpoints first")); @@ -114,7 +116,7 @@ suite('GenerateClientCommand Test Suite', () => { const generateStepsFn = sinon.stub(generateStepsModule, "generateSteps"); generateStepsFn.resolves(config); const showUpgradeWarningMessageStub = sinon.stub(msgUtilitiesModule, "showUpgradeWarningMessage"); - const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext); + const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext, myOutputChannel); await generateClientCommand.execute(); assert.strictEqual((treeProvider.getSelectedPaths()).length, 1); vscodeWindowSpy.verify(); @@ -162,7 +164,7 @@ suite('GenerateClientCommand Test Suite', () => { deepLinkParamsHandler.setDeepLinkParams(pluginParams); //stub and call generateCommand - const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext); + const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext, myOutputChannel); const generatePluginAndRefreshUIExpectation = sinon.mock(generateClientCommand).expects( "generatePluginAndRefreshUI").once().withArgs( config, extensionSettings, "path/to/temp/folder", ["repairs"] @@ -173,7 +175,7 @@ suite('GenerateClientCommand Test Suite', () => { assert.strictEqual(!treeProvider.descriptionUrl, false); vscodeWindowSpy.verify(); sinon.assert.calledOnceWithMatch(getlanguageInfoFn, context); - let stateInfo = transformToGenerationConfig(pluginParams); + let stateInfo = await transformToGenerationConfig(pluginParams); sinon.assert.calledOnceWithMatch(generateStepsFn, stateInfo, undefined , pluginParams); sinon.assert.calledOnce(showUpgradeWarningMessageStub); sinon.assert.calledOnceWithMatch(getExtensionSettingsStub, "kiota"); @@ -216,8 +218,8 @@ suite('GenerateClientCommand Test Suite', () => { deepLinkParamsHandler.setDeepLinkParams(pluginParams); //stub and call generateCommand - const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext); - var outputPath = "path/to/temp/folder/appPackage"; + const generateClientCommand = new generateModule.GenerateClientCommand(treeProvider, context, viewProvider, setWorkspaceGenerationContext, myOutputChannel); + var outputPath = path.join("path", "to", "temp", "folder", "appPackage"); //make it os agnostic const generateManifestAndRefreshUIExpectation = sinon.mock(generateClientCommand).expects( "generateManifestAndRefreshUI").twice().withArgs( config, extensionSettings, outputPath, ["repairs"] diff --git a/vscode/microsoft-kiota/src/util.ts b/vscode/microsoft-kiota/src/util.ts index c61ab8fcb4..b07930e64d 100644 --- a/vscode/microsoft-kiota/src/util.ts +++ b/vscode/microsoft-kiota/src/util.ts @@ -171,3 +171,5 @@ export function isValidUrl(url: string): boolean { return false; } } + + diff --git a/vscode/microsoft-kiota/src/utilities/deep-linking.ts b/vscode/microsoft-kiota/src/utilities/deep-linking.ts index c7b5dbfc30..d9d2c2567f 100644 --- a/vscode/microsoft-kiota/src/utilities/deep-linking.ts +++ b/vscode/microsoft-kiota/src/utilities/deep-linking.ts @@ -1,3 +1,6 @@ +import * as path from 'path'; +import { promises as fs } from 'fs'; + import { GenerateState } from "../modules/steps/generateSteps"; import { KiotaGenerationLanguage, KiotaPluginType } from "../types/enums"; import { allGenerationLanguagesToString, getSanitizedString, parseGenerationLanguage, parsePluginType } from "../util"; @@ -8,8 +11,8 @@ export function isDeeplinkEnabled(deepLinkParams: Partial): b return Object.values(deepLinkParams).filter(property => property).length >= minimumNumberOfParams; } -export function transformToGenerationConfig(deepLinkParams: Partial) - : Partial { +export async function transformToGenerationConfig(deepLinkParams: Partial) + : Promise> { const generationConfig: Partial = {}; if (deepLinkParams.kind === "client") { generationConfig.generationType = "client"; @@ -34,7 +37,7 @@ export function transformToGenerationConfig(deepLinkParams: Partial): @@ -59,6 +63,8 @@ export function validateDeepLinkQueryParams(queryParameters: Partial -1 ? lowercasedKind : undefined; if (!validKind) { @@ -103,14 +109,38 @@ export function validateDeepLinkQueryParams(queryParameters: Partial): Promise { + if (deepLinkParams.projectPath) { + try { + const exists = await fs.access(deepLinkParams.projectPath).then(() => true).catch(() => false); + if (!exists) { + try { + await fs.mkdir(deepLinkParams.projectPath); + } catch (err: unknown) { + throw new Error(`Error creating directory: ${(err as Error).message}`); + } + } + return deepLinkParams.projectPath; + } catch (error) { + return createTemporaryFolder(); + } + } + return createTemporaryFolder(); +} diff --git a/vscode/microsoft-kiota/src/utilities/logging.ts b/vscode/microsoft-kiota/src/utilities/logging.ts index 616e822965..64228de614 100644 --- a/vscode/microsoft-kiota/src/utilities/logging.ts +++ b/vscode/microsoft-kiota/src/utilities/logging.ts @@ -1,18 +1,14 @@ import * as vscode from 'vscode'; +import { LogOutputChannel } from 'vscode'; import { getLogEntriesForLevel, KiotaLogEntry, LogLevel } from '../kiotaInterop'; -let kiotaOutputChannel: vscode.LogOutputChannel; -kiotaOutputChannel = vscode.window.createOutputChannel("Kiota", { - log: true, -}); - -export async function exportLogsAndShowErrors(result: KiotaLogEntry[]): Promise { +export async function exportLogsAndShowErrors(result: KiotaLogEntry[], kiotaOutputChannel: LogOutputChannel): Promise { const errorMessages = result ? getLogEntriesForLevel(result, LogLevel.critical, LogLevel.error) : []; result.forEach((element) => { - logFromLogLevel(element); + logFromLogLevel(element, kiotaOutputChannel); }); if (errorMessages.length > 0) { await Promise.all(errorMessages.map((element) => { @@ -21,7 +17,7 @@ export async function exportLogsAndShowErrors(result: KiotaLogEntry[]): Promise< } } -function logFromLogLevel(entry: KiotaLogEntry): void { +export function logFromLogLevel(entry: KiotaLogEntry, kiotaOutputChannel: LogOutputChannel): void { switch (entry.level) { case LogLevel.critical: case LogLevel.error: @@ -41,3 +37,18 @@ function logFromLogLevel(entry: KiotaLogEntry): void { break; } } + +export async function checkForSuccess(results: KiotaLogEntry[]) { + for (const result of results) { + if (result && result.message) { + if (result.message.includes("Generation completed successfully")) { + return true; + } + } + } + return false; +} + +export function showLogs(kiotaOutputChannel: LogOutputChannel): void { + kiotaOutputChannel.show(); +}